Impworks
Impworks

Reputation: 2818

NHibernate: map class with several inheritance fields

I have the following entities in my project which I want to map using NHibernate Attributes:

public interface IContent
{
    int Id { get; set; }
    string Name { get; set; }
}

public interface IUser
{
    int Id { get; set; }
}

[Class]
public class Book : IContent
{
    [Id(...), Column(...), Generator(...)]
    public virtual int Id { get; set; }

    public virtual string Name { get; set; }
}

[Class]
public class Collection : IContent
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
}

[Class]
public class Reader : IUser
{
    [Id(...), Column(...), Generator(...)]
    public virtual int Id { get; set; }

    [Property]
    public virtual string Email { get; set; }
}

[Class]
public class ReaderGroup : IUser
{
    [Id(...), Column(...), Generator(...)]
    public virtual int Id { get; set; }

    [ManyToMany(...)]
    public virtual ISet<Reader> Readers { get; set; }
}

And now I want to implement a unified access control mechanism:

public class AccessPermission
{
    [Id(...), Column(...), Generator(...)]
    public virtual int Id { get; set; }

    public virtual IContent Object { get; set; }

    public virtual IUser Subject { get; set; }
}

The trick is that there are two fields which accept different types of values: Object and Subject. I have previously used Discriminator and Subclass attributes, but then there was only one field with inherited types, not two or more.

Is there a smart way to implement such a case?

Upvotes: 0

Views: 2237

Answers (1)

dav_i
dav_i

Reputation: 28157

NHibernate doesn't really play nice with interfaces as the way it works is by creating proxies of classes by inheriting your entities (hence why you have to define all your fields as virtual).

What I would do is instead of your interfaces here, use abstract classes, e.g.

public abstract class User
{
    public virtual int Id { get; protected set; }
    public virtual IEnumerable<AccessPermission> AccessPermissions { get; protected set; }
}

Then (using Fluent NHibernate)

public class UserMap : ClassMap<User>
{
    public UserMap()
    {
        this.Id(x => x.Id);
        this.HasMany(x => x.AccessPermissions);
        this.DiscriminateSubClassesOnColumn("Type");
    }
}

and for your sub-classes:

public class ReaderMap : SubClassMap<Reader>
{
    public ReaderMap()
    {
        this.DiscriminatorValue("Reader");
        this.Map(x => x.Email);
    }
}

for your AccessPermission:

public class AccessPermissionMap : ClassMap<AccessPermission>
{
    public AccessPermissionMap()
    {
        this.Id(x => x.Id);
        this.References(x => x.Object);
        this.References(x => x.Subject);
    }
}

Then NH does all the hard work for you and will figure out what sub-class to instantiate based on the FK id in your AccessPermission

Upvotes: 1

Related Questions