Быстрая автоматическая таблица NHibernate-таблица-на-абстрактный-иерархия / таблица-на-конкретный подкласс - PullRequest
4 голосов
/ 27 декабря 2011

У меня есть классы

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, но даже отображения иерархии (таблица-на-абстракт-иерархия / таблица-на-конкретный-подкласс), похоже, не сработали.

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

Как получить тот же результат с автоппингами?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...