Free NHibernate auto-create table-for-abstract hierarchy / table per concrete subclass

I have classes

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

And as a result, I would like to have the following tables. I tried to implement many different IConventions, but even hierarchy mappings (table for abstraction-hierarchy / table for specific subclass) seem to fail.

 Content Id Type (discriminator) ParentId Created Slug Path Title Content_Tags (Tags from ITaggable) ContentId TagId Content$Foo Bar Content$Foo_Related ParentFooId ChildPageId 

I already have ugly, working smooth mappings, but I would like to get rid of some ugliness

 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 => xP[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); } } 

How to get the same result with AutoCorrect?

+4
source share

Source: https://habr.com/ru/post/1388086/


All Articles