流畅的NHibernate自动化每个抽象层次表/每个具体的表 - 子类

时间:2011-12-27 05:49:29

标签: fluent-nhibernate joined-subclass table-per-hierarchy

我有课程

public abstract class Content : IContent
{
    public virtual Guid Id { get; protected set; }
    public virtual IPage Parent { get; set; }
    public virtual DateTime Created { get; set; }
    /* ... */
}
public abstract class Page : Content, IPage
{
    public virtual string Slug { get; set; }
    public virtual string Path { get; set; }
    public virtual string Title { get; set; }
    /* ... */
}

public class Foo : Page, ITaggable
{
    // this is unique property 
    // map to joined table
    public virtual string Bar { get; set; }

    // this is a unique collection
    public virtual ISet<Page> Related { get; set; }

    // this is "shared" property (from ITaggable)
    // map to shared table
    public virtual ISet<Tag> Tags { get; set; }
}

结果我想要下面的表格。我尝试过实现大量不同的IConventions,但即使是层次结构映射(table-per-abstract-hierarchy / table-per-concrete-subclass)也似乎失败了。

Content
    Id
    Type (discriminator)
    ParentId
    Created
    Slug
    Path
    Title

Content_Tags (Tags from ITaggable)
    ContentId
    TagId

Content$Foo
    Bar

Content$Foo_Related
    ParentFooId
    ChildPageId

我已经有了丑陋,工作流畅的映射,但我想摆脱一些丑陋

public class ContentMapping : ClassMap<Content>
{
    public ContentMapping()
    {
        Table("Content");
        Id(x => x.Id).GeneratedBy.GuidComb();
        References<Page>(x => x.Parent, "ParentId");
        Map(x => x.Created);

        DiscriminateSubClassesOnColumn("Type");
    }
}
public class PageMapping : SubclassMap<Page>
{
    public PageMapping()
    {
        Map(x => x.Slug);
        Map(x => x.Path);
        Map(x => x.Title);
    }
}
public class ConcreteContentMapping<T> : SubclassMap<T> where T : Content, new()
{
    public ConcreteContentMapping() : this(true) { }
    protected ConcreteContentMapping(bool mapJoinTable)
    {
        DiscriminatorValue(typeof(T).FullName);
        MapCommonProperties();

        if(mapJoinTable)
        {
            MapJoinTableWithProperties(CreateDefaultJoinTableName(), GetPropertiesNotFrom(GetContentTypesAndInterfaces().ToArray()));
        }
    }

    private void MapCommonProperties()
    {
        if (typeof(ITagContext).IsAssignableFrom(typeof(T)))
        {
                Map(x => ((ITagContext)x).TagDirectory);
        }
        if (typeof(ITaggable).IsAssignableFrom(typeof(T)))
        {
                HasManyToMany(x => ((ITaggable)x).Tags).Table("Content_Tags").ParentKeyColumn("ContentId").ChildKeyColumn("TagId").Cascade.SaveUpdate();
        }
    }
    /* ... */

    // something I would like to get rid of with automappings...
    protected void MapCollectionProperty(JoinPart<T> table, PropertyInfo p)
    {
        var tableName = ((IJoinMappingProvider)table).GetJoinMapping().TableName + "_" + p.Name;
        var elementType = p.PropertyType.GetGenericArguments()[0];

        var method = table.GetType().GetMethods().Where(m => m.Name == "HasManyToMany")
            .Select(m => new { M = m, P = m.GetParameters() })
            .Where(x => x.P[0].ParameterType.GetGenericArguments()[0].GetGenericArguments()[1] == typeof(object))
            .FirstOrDefault().M.MakeGenericMethod(elementType);

        dynamic m2m = method.Invoke(table, new object[] { MakePropertyAccessExpression(p)});
        m2m.Table(tableName).ParentKeyColumn("Parent" + typeof(T).Name + "Id").ChildKeyColumn("Child" + elementType.Name + "Id");
    }
    protected Expression<Func<T, object>> MakePropertyAccessExpression(PropertyInfo property)
    {
        var param = Expression.Parameter(property.DeclaringType, "x");
        var ma = Expression.MakeMemberAccess(param, property);
        return Expression.Lambda<Func<T, object>>(ma, param);
    }
}

如何通过自动化获得相同的结果?

0 个答案:

没有答案