简体   繁体   中英

Fluent NHibernate: ISet of base class

In my project I have a base class (not mapped):

public abstract class BaseEntity
{
    public virtual string Name { get; set; }
    public virtual string Description { get; set; }
}

Also I have a few inherited classes (they look all almost the same, so here is a code and map for only one)

public class User : BaseEntity
{
    public virtual int UserId { get; set; }
    public virtual string Login { get; set;  }
    public virtual string PasswordHash { get; set; }

    public virtual ISet<BaseEntity> Entities { get; set; }
}

public class UserMap : ClassMap<User>
{
    public UserMap()
    {
        this.Id(x => x.UserId);
        this.Map(x => x.Login);
        this.Map(x => x.PasswordHash);
        this.HasManyToMany<BaseEntity>(x => x.Entities);
    }
}

Next, I have a NHibernateHelper:

public class NHibernateHelper
{
    public static ISession OpenSession()
    {
        ISessionFactory sessionFactory = Fluently.Configure()
            .Database(MsSqlConfiguration.MsSql2008.ConnectionString(@"someconstring")
            .ShowSql()
        )
        .Mappings(m => m.FluentMappings.AddFromAssemblyOf<User>())

        .ExposeConfiguration(cfg => new SchemaUpdate(cfg).Execute(false, true))

        .BuildSessionFactory();
        return sessionFactory.OpenSession();
    }
}

And here is a question:

How can I exclude BaseEntity class from mapping, if I need table like EnitiyToEntity in my Database for many-to-many relationship?

Take a look to this: https://www.codeproject.com/Articles/232034/Inheritance-mapping-strategies-in-Fluent-Nhibernat

If I understand your question the solution should be to implement TPC (Table per concrete class).

By the way, in your mapping you have to use the concrete type for HasManyToMany .

For example (I supposed your user is referenced to many groups):

 HasManyToMany<Group>(x => x.Entities).Table("UsersGroups");

where the Group class is something like this:

    public class Group : BaseEntity
    {
        public virtual int GroupId { get; set; }
        public virtual string PasswordHash { get; set; }
        public virtual ISet<BaseEntity> Members { get; set; }
    }

And in the GroupMap class you can reference the users like this:

  HasManyToMany<User>(x => x.Members).Table("UsersGroups");

If you reference a class you have to map it. So map Entity as ClassMap and all the others as SubclassMap. They will end up as union subclass which is one table per class. Unfortunatly you can not map a hasmanytoany with FNH. You can map it as hasmanytomany and work around it:

    var config = new Configuration();

    config.BeforeBindMapping += BeforeBindMapping;
    _config = Fluently
        .Configure(config)
        ...

    private void BeforeBindMapping(object sender, NHCfg.BindMappingEventArgs e)
    {
        var userclass = e.Mapping.RootClasses.FirstOrDefault(rc => rc.name.StartsWith(typeof(User).FullName));
        if (userclass != null)
        {
            HbmSet prop = (HbmSet)paymentclass.Properties.FirstOrDefault(rc => rc.Name == "Entities");
            prop.Item = new HbmManyToAny // == prop.ElementRelationship
            {
                column = new[]
                    {
                        new HbmColumn { name = "entityType", notnull = true, notnullSpecified = true },
                        new HbmColumn { name = "entity_id", notnull = true, notnullSpecified = true }
                    },
                idtype = "Int64",
                metatype = "String",
                metavalue = typeof(Entity).Assembly.GetTypes()
                    .Where(t => !t.IsInterface && !t.IsAbstract && typeof(Entity).IsAssignableFrom(t))
                    .Select(t => new HbmMetaValue { @class = t.AssemblyQualifiedName, value = t.Name })
                    .ToArray()
            };
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM