在运行时扩展/修改 NHibernate 类
很抱歉,如果已经有一个正确的答案,但我还没有找到。我正在使用 NH3,并且有一个用例,我想将 Set 添加到类实现特定接口的任何实体上。我有一个配置生成器类,因此我可以在创建会话工厂之前进行这些更改。
给出这个简化的示例:
public class Person : IHasExtraItems
{
public Person()
{
this.ExtraItems = new HashSet<ExtraItem>();
}
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual DateTime Birthdate { get; set; }
public virtual ICollection<ExtraItem> ExtraItems { get; protected set; }
}
public class ExtraItem
{
public virtual Guid Id { get; set; }
}
以及这个示例映射:
<class name="Person">
<id name="Id">
<generator class="guid"/>
</id>
<property name="Name"/>
<property name="Birthdate"/>
<set name="Extra" table="PersonExtraItems" cascade="all">
<key column="PersonId"/>
<many-to-many column="ExtraItemId" class="ExtraItem" unique="true" />
</set>
</class>
由于我希望能够透明地将此功能应用于许多类 - 只需实现接口 - 我不想将“ExtraItem”放入映射中。相反,我想在运行时添加它。因此,如果我从 xml 映射中删除该属性,如何在运行时添加它?
这准确地描述了我想要做出的改变的类型: http://ayende.com/Blog/archive /2008/05/01/Dynamic-Mapping-with-NHibernate.aspx
但它并没有映射多对多集合,而且我脆弱的大脑无法破译 nhibernate 用于的内存中映射表示创造效果。这是我得到的最接近的结果,基于尝试在调试器中获取可见的属性以匹配
foreach (var cls in cfg.ClassMappings)
{
if (typeof(IHasExtraItems).IsAssignableFrom(cls.MappedClass))
{
NHibernate.Mapping.Property property = new NHibernate.Mapping.Property();
NHibernate.Mapping.Set value = new NHibernate.Mapping.Set(cls);
value.Role = cls.EntityName + ".ExtraItems";
value.IsGeneric = true;
var table = new Table();
table.Name = cls.MappedClass.Name + "ExtraItems";
value.CollectionTable = table;
value.GenericArguments = new Type[] { typeof(ExtraItem) };
value.IsOptimisticLocked = true;
value.IsLazy = true;
mappings.AddCollection(value);
property.Value = value;
property.Name = "ExtraItems";
property.PersistentClass = cls;
property.Cascade = "all";
cls.AddProperty(property);
}
}
在测试中,这会产生运行时错误,因为键为空,但是 XML 映射版本可以工作,并且看起来或多或少相同我做出改变的时间。
奖励分:我想要一个多对多,特别是因为我想要一个连接表。这使我可以将实体映射到具有真正外键的扩展数据以提高性能。 ExtraItems 实际上应该是值类型而不是真正的实体,但我无法弄清楚如何映射它,即使在 XML 中也是如此。
奖励积分,第 2 部分:我可以使用 confORM 来完成此操作吗?我不想将所有现有映射切换到confORM,而且我找不到将confORM 与传统XML 映射混合的示例,更不用说修改现有映射了。 Fluent 是另一种选择,但我使用的是 NH3,而且我认为 Fluent 还不支持这一点。
提前致谢!
编辑 我相当确定我的问题是我没有定义集合的元素。但是,我无法辨别如何正确定义集合的元素。
Apologies if there's an on point answer already out there but I haven't found it. I'm using NH3 and I've got a use case where I want to add a Set onto any entity who's class implements a specific interface. I have a configuration builder class so I can make these changes before creating the session factory.
Given this reduced example:
public class Person : IHasExtraItems
{
public Person()
{
this.ExtraItems = new HashSet<ExtraItem>();
}
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual DateTime Birthdate { get; set; }
public virtual ICollection<ExtraItem> ExtraItems { get; protected set; }
}
public class ExtraItem
{
public virtual Guid Id { get; set; }
}
And this example mapping:
<class name="Person">
<id name="Id">
<generator class="guid"/>
</id>
<property name="Name"/>
<property name="Birthdate"/>
<set name="Extra" table="PersonExtraItems" cascade="all">
<key column="PersonId"/>
<many-to-many column="ExtraItemId" class="ExtraItem" unique="true" />
</set>
</class>
Since I want to be able to apply this functionality to many classes transparently -- just by implementing the interface -- I don't want to put the "ExtraItem" in the mapping. Instead I want to add it at runtime. So if I remove the property from the xml mapping, how can I add this at runtime?
There's this describing exactly the type of change I'm trying to make:
http://ayende.com/Blog/archive/2008/05/01/Dynamic-Mapping-with-NHibernate.aspx
But it doesn't map a many to many set, and my feeble brain has been unable to decipher the in-memory mapping representation nhibernate uses to create the effect. This is the closest I've come, based on trying to get properties visible in the debugger to match
foreach (var cls in cfg.ClassMappings)
{
if (typeof(IHasExtraItems).IsAssignableFrom(cls.MappedClass))
{
NHibernate.Mapping.Property property = new NHibernate.Mapping.Property();
NHibernate.Mapping.Set value = new NHibernate.Mapping.Set(cls);
value.Role = cls.EntityName + ".ExtraItems";
value.IsGeneric = true;
var table = new Table();
table.Name = cls.MappedClass.Name + "ExtraItems";
value.CollectionTable = table;
value.GenericArguments = new Type[] { typeof(ExtraItem) };
value.IsOptimisticLocked = true;
value.IsLazy = true;
mappings.AddCollection(value);
property.Value = value;
property.Name = "ExtraItems";
property.PersistentClass = cls;
property.Cascade = "all";
cls.AddProperty(property);
}
}
In a test, this produces a runtime error because the key is null, however the XML mapped version works, and looks more or less identical at the time I'm making the changes.
Bonus points: I want a many-to-many specifically because I want a joined table. This lets me map an entity to the extending data with true foreign keys for performance. The ExtraItems should really be a value type rather than a true entity, but I couldn't figure out how to map that, even in XML.
Bonus points, part 2: Could I do this with confORM? I don't want to switch all my existing mappings to confORM, and I couldn't find an example of mixing confORM with conventional XML mappings, nevermind modifying existing mappings. Fluent would be another option, but I'm using NH3 and I don't think Fluent supports that yet.
Thanks in advance!
EDIT I'm fairly certain that my issue is that I'm not defining the elements of the set. However, I can't discern how to define the elements of the set properly.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
有 NH3 的 Fluent 版本,因此您可以使用它(我这样做),如果您使用 Fluent,您可以很容易地通过约定来完成此操作。您在奖励积分部分提到了这一点,所以也许您应该再看一下?
There are builds of fluent for NH3, so you can use it (I do), and if you are using fluent you can very easily do this with a convention. You mention that in your bonus points section, so maybe you should give it another look?