0

我使用 FluentNHibernate (Automapping) 进行映射,使用 NHibernate 3.2 进行数据访问,使用 SchemaExport 生成我的数据库。

我有一个类,它是andPrincipal的基类。 有一个类型的属性。 有 2 套:和。UserUsergroupPrincipalCommonThingCommonThingCommonThingManagedUsersManagedUsergroups

现在CommonThingIdPrincipals-table (OK)、- Userstable (WRONG)、- Usergroupstable (WRONG) 生成一列。

如何让 FluentNHibernate只生成 -table 中的列Principals不是子类表?

编辑:类和映射主要:

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
{
    ...
}

共同点:

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()            
            ;
        ...
    }
}


华拉巴

4

2 回答 2

0

mapping.HasMany(x => x.ManagedUsers)mapping.HasMany(x => x.ManagedUsergroups)负责额外的CommonThingId列。

那应该这样做:

mapping.HasMany<Principal>(x => x.ManagedUsers)
mapping.HasMany<Principal>(x => x.ManagedUsergroups)

我无法抗拒。我认为多态在这里会更好

public virtual CommonThing CommonThing
{
    get { return _commonThing; }
    set
    {
        if (_commonThing == value)
            return;

        _commonThing = value;

        if (_commonThing != null)
            AddThisToCommonThing(_commonThing);
    }
}

protected abstract void AddThisToCommonThing(CommonThing common);

编辑:@comment:对,我还没有看到这个

你可以为用户做一个 TPH (table-per-hirarchy) 映射:在 fluentnhibernate 自动映射配置中override DiscriminateSubclasses() { return true; }

class SCConvention : ISubclassConvention
{
    Apply(...)
    {
        instance.DiscriminatorValue(instance.Type.Name);
    }
}

mapping.HasMany<Principal>(x => x.ManagedUsers).Where("discriminatorcolumn = 'User'")
mapping.HasMany<Principal>(x => x.ManagedUsergroups).Where("discriminatorcolumn = 'Usergroup'")
于 2011-08-24T10:54:55.207 回答
0

所以我终于找到了一种方法来防止已经映射的映射引用:

public class AutomappingConfiguration : DefaultAutomappingConfiguration
{
    ...
    public override bool ShouldMap(Member member)
    {
        ...
        var res = base.ShouldMap(member);
        if (res == true &&              
            typeof(IEnumerable).IsAssignableFrom(member.PropertyType) == false) // "References"
        {
            var originalDeclaringType = GetOriginalDeclaringType(member.MemberInfo);

            // is Reference declared in a base-type?
            if (!(originalDeclaringType == typeof(Entity) ||
                originalDeclaringType == typeof(Entity<int>)) &&
                originalDeclaringType != member.MemberInfo.ReflectedType)
                return false; // base-type already mapped it...
        }
        return res;
    }

    // Helper
    private Type GetOriginalDeclaringType(MemberInfo member)
    {
        List<Type> types = new List<Type>();

        Type type = member.ReflectedType;
        while (type != null)
        {
            types.Add(type);
            type = type.BaseType;
        }

        types.Reverse();

        foreach(var t in types)
        {
            var tmp = t.GetMember(member.Name, BindingFlags.Public |
                        BindingFlags.NonPublic |
                        BindingFlags.Instance |
                        BindingFlags.DeclaredOnly);
            if (tmp.Length != 0)
            {
                type = t;
                break;
            }
        }
        return type;
    }
    ...
}

可能有些情况会因此导致副作用,但在我目前非常非常复杂的项目中,它只是做了我想要的。


华拉巴

于 2011-08-25T12:38:25.630 回答