NHibernate:JoinedSubclass,HasMany
我使用 FluentNHibernate(自动映射)进行映射,使用 NHibernate 3.2 进行数据访问,使用 SchemaExport 生成数据库。
我有一个类 Principal
,它是 User
和 Usergroup
的基类。 Principal
具有 CommonThing
类型的属性 CommonThing
。 CommonThing
有 2 个集合:ManagedUsers
和 ManagedUsergroups
。
现在,为 Principals
-table (OK)、Users
-table (WRONG)、Usergroups
生成列 CommonThingId
-表(错误)。
如何让 FluentNHibernate 仅生成 Principals
-table 中的列,而不生成子类表?
编辑:类和映射 主体:
public abstract class Principal : Entity
{
...
public virtual CommonThing CommonThing
{
get
{
return _commonThing;
}
set
{
if (_commonThing == value)
return;
_commonThing = value;
if (_commonThing == null)
return;
if (this is Usergroup)
_commonThing.AddUsergroup(this as Usergroup);
else if (this is User)
_commonThing.AddUser(this as User);
}
}
...
}
用户:
public partial class User : Principal
{
...
}
用户组:
public partial class Usergroup : Principal
{
...
}
CommonThing:
public class CommonThing : Entity
{
...
public virtual IEnumerable<User> ManagedUsers { get { return _managedUsers; } set { _managedUsers = (Iesi.Collections.Generic.ISet<User>)value; } }
public virtual IEnumerable<Usergroup> ManagedUsergroups { get { return _managedUsergroups; } set { _managedUsergroups = (Iesi.Collections.Generic.ISet<Usergroup>)value; } }
...
}
约定:
public class ReferenceConvention : IReferenceConvention
{
public void Apply(IManyToOneInstance instance)
{
var keyName = string.Format(CultureInfo.InvariantCulture, "FK_MtO_{0}_in_{1}_{2}",
instance.Property.PropertyType.Name,
instance.EntityType.Name,
instance.Name);
instance.ForeignKey(keyName);
instance.LazyLoad();
instance.Cascade.SaveUpdate();
instance.Column(instance.Property.PropertyType.Name + "Id");
instance.Access.CamelCaseField(CamelCasePrefix.Underscore);
}
}
public class ForeignKeyConvention : FluentNHibernate.Conventions.ForeignKeyConvention
{
protected override string GetKeyName(Member property, Type type)
{
if (property == null)
return type.Name + "Id";
return property.Name + "Id";
}
}
public class HasManyConvention : IHasManyConvention
{
public void Apply(IOneToManyCollectionInstance instance)
{
var keyName = string.Format(CultureInfo.InvariantCulture, "FK_OtM_{0}_{1}2{2}",
instance.Member.ReflectedType.Name,
instance.Member.Name,
instance.EntityType.Name);
instance.Key.ForeignKey(keyName);
if(instance.Key.Columns.Count() != 0)
instance.Inverse();
instance.Cascade.SaveUpdate();
instance.Cache.ReadWrite();
instance.Cache.IncludeAll();
instance.Access.CamelCaseField(CamelCasePrefix.Underscore);
}
}
public class JoinedSubclassConvention : IJoinedSubclassConvention
{
public void Apply(IJoinedSubclassInstance instance)
{
instance.Table("" + Inflector.Net.Inflector.Pluralize(instance.Type.Name));
instance.Key.Column("Id");
instance.DynamicInsert();
instance.DynamicUpdate();
instance.LazyLoad();
}
}
主体映射:
public class PrincipalMapping : IAutoMappingOverride<Principal>
{
public void Override(AutoMapping<Principal> mapping)
{
...
mapping.References(x => x.CommonThing)
.LazyLoad()
.Nullable()
.Access.CamelCaseField(Prefix.Underscore)
.Cascade.None();
;
mapping.JoinedSubClass<User>("Id");
mapping.JoinedSubClass<Usergroup>("Id");
...
}
}
CommonThing 映射:
public class CommonThingMapping : IAutoMappingOverride<CommonThing>
{
public void Override(AutoMapping<CommonThing> mapping)
{
...
mapping.HasMany(x => x.ManagedUsers)
.AsSet()
.ExtraLazyLoad()
;
mapping.HasMany(x => x.ManagedUsergroups)
.ExtraLazyLoad()
.AsSet()
;
...
}
}
Lg
瓦拉帕
I use FluentNHibernate (Automapping) for mapping, NHibernate 3.2 for data access and SchemaExport to generate my database.
I have a class Principal
which is the base class for User
and Usergroup
.Principal
has a property CommonThing
of type CommonThing
.CommonThing
has 2 sets: ManagedUsers
and ManagedUsergroups
.
Now a column CommonThingId
is generated for Principals
-table (OK), Users
-table (WRONG), Usergroups
-table (WRONG).
How can I get FluentNHibernate to only generate the column in Principals
-table and not the subclassed tables?
Edit: Classes & Mappings
Principal:
public abstract class Principal : Entity
{
...
public virtual CommonThing CommonThing
{
get
{
return _commonThing;
}
set
{
if (_commonThing == value)
return;
_commonThing = value;
if (_commonThing == null)
return;
if (this is Usergroup)
_commonThing.AddUsergroup(this as Usergroup);
else if (this is User)
_commonThing.AddUser(this as User);
}
}
...
}
User:
public partial class User : Principal
{
...
}
Usergroup:
public partial class Usergroup : Principal
{
...
}
CommonThing:
public class CommonThing : Entity
{
...
public virtual IEnumerable<User> ManagedUsers { get { return _managedUsers; } set { _managedUsers = (Iesi.Collections.Generic.ISet<User>)value; } }
public virtual IEnumerable<Usergroup> ManagedUsergroups { get { return _managedUsergroups; } set { _managedUsergroups = (Iesi.Collections.Generic.ISet<Usergroup>)value; } }
...
}
Conventions:
public class ReferenceConvention : IReferenceConvention
{
public void Apply(IManyToOneInstance instance)
{
var keyName = string.Format(CultureInfo.InvariantCulture, "FK_MtO_{0}_in_{1}_{2}",
instance.Property.PropertyType.Name,
instance.EntityType.Name,
instance.Name);
instance.ForeignKey(keyName);
instance.LazyLoad();
instance.Cascade.SaveUpdate();
instance.Column(instance.Property.PropertyType.Name + "Id");
instance.Access.CamelCaseField(CamelCasePrefix.Underscore);
}
}
public class ForeignKeyConvention : FluentNHibernate.Conventions.ForeignKeyConvention
{
protected override string GetKeyName(Member property, Type type)
{
if (property == null)
return type.Name + "Id";
return property.Name + "Id";
}
}
public class HasManyConvention : IHasManyConvention
{
public void Apply(IOneToManyCollectionInstance instance)
{
var keyName = string.Format(CultureInfo.InvariantCulture, "FK_OtM_{0}_{1}2{2}",
instance.Member.ReflectedType.Name,
instance.Member.Name,
instance.EntityType.Name);
instance.Key.ForeignKey(keyName);
if(instance.Key.Columns.Count() != 0)
instance.Inverse();
instance.Cascade.SaveUpdate();
instance.Cache.ReadWrite();
instance.Cache.IncludeAll();
instance.Access.CamelCaseField(CamelCasePrefix.Underscore);
}
}
public class JoinedSubclassConvention : IJoinedSubclassConvention
{
public void Apply(IJoinedSubclassInstance instance)
{
instance.Table("" + Inflector.Net.Inflector.Pluralize(instance.Type.Name));
instance.Key.Column("Id");
instance.DynamicInsert();
instance.DynamicUpdate();
instance.LazyLoad();
}
}
Principal mapping:
public class PrincipalMapping : IAutoMappingOverride<Principal>
{
public void Override(AutoMapping<Principal> mapping)
{
...
mapping.References(x => x.CommonThing)
.LazyLoad()
.Nullable()
.Access.CamelCaseField(Prefix.Underscore)
.Cascade.None();
;
mapping.JoinedSubClass<User>("Id");
mapping.JoinedSubClass<Usergroup>("Id");
...
}
}
CommonThing mapping:
public class CommonThingMapping : IAutoMappingOverride<CommonThing>
{
public void Override(AutoMapping<CommonThing> mapping)
{
...
mapping.HasMany(x => x.ManagedUsers)
.AsSet()
.ExtraLazyLoad()
;
mapping.HasMany(x => x.ManagedUsergroups)
.ExtraLazyLoad()
.AsSet()
;
...
}
}
Lg
warappa
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
mapping.HasMany(x => x.ManagedUsers)
和mapping.HasMany(x => x.ManagedUsergroups)
负责额外的CommonThingId
代码>-列。应该这样做:
我无法抗拒。我认为多态性在这里会更好
编辑:@comment:对,我还没有看到这一点,
你可以为用户做一个 TPH(每个层级表)映射:在 Fluentnhibernate 自动映射配置中
override DiscriminateSubclasses()
{
返回真;
}
mapping.HasMany(x => x.ManagedUsers)
andmapping.HasMany(x => x.ManagedUsergroups)
are responsible for the extraCommonThingId
-columns.That should do:
and i couldnt resist. I think polymorphism would be better here
Edit: @comment: right i havent seen this
you could do a TPH (table-per-hirarchy) mapping for Users: in fluentnhibernate automapping configuration
override DiscriminateSubclasses()
{
return true;
}
所以我终于找到了一种方法来防止映射已经映射的引用:
可能存在因此而导致副作用的情况,但在我当前的非常非常复杂的项目中,它只是做了什么我想要它。
LG
瓦拉帕
So I finally found a way to prevent mapping references which are already mapped:
It can be that there are cases which cause side effects due to this, but in my current very, very complex project it just did what I wanted it to.
Lg
warappa