fluent nhibernate - Many to Many mapping with attribute

后端 未结 2 991
南方客
南方客 2021-01-01 07:29

I have 2 master tables which are linked by a map table as below

User [UserId,Name]

Resource [ResourceId,Name]

UserResourceMap [UserId,ResourceId,AccessLeve         


        
相关标签:
2条回答
  • 2021-01-01 08:11

    Your domain model does not seem to match your database model - the Resource class has the property AccessLevel (i.e. one AccessLevel per Resource) but in the DB model AccessLevel is a column on the map table (i.e. one AccessLevel per User-Resource relation).

    Assuming the DB model is the correct model one (fairly straightforward) way of mapping this would be to introduce a class like this.

    public class UserResource {
    
      public virtual int UserResourceId { get; protected set; }
      public virtual User User { get; set; }
      public virtual Resource { get; set; }
      public virtual string AccessLevel { get; set; }
    }
    

    and map it in this way:

    public class UserResourceMap : ClassMap<UserResource> {
    
      public UserResourceMap() {
    
        Table("UserResourceMap");
        Id(x => x.UserResourceId);
        References(x => x.User).UniqueKey("UniqueUserAndResource");
        References(x => x.Resource).UniqueKey("UniqueUserAndResource");
        Map(x => x.AccessLevel);
      }
    }
    

    If you want bidirectional associations you could also add a Collection property on User and/or Resource and map these with HasMany(...).Inverse(). Of course, this kind of mapping would introduce a new UserResourceId column in the UserResourceMap table (using a composite key consisting of User and Resource would mitigate that).

    Another solution would be to add an EntityMap association. If the association is owned by User it would be a Dictionary<Resource, string> property. Something like this might do the trick:

    public class User {
      public virtual int UserId { get; protected set; }
      public virtual string Name { get; set; }
      public virtual Dictionary<Resource, string> Resources { get; set; } // Resource -> AccessLevel
    }
    
    public class UserMap : ClassMap<User> {
    
      public UserMap() {
    
        Table("User");
        Id(x => x.UserId);
        Map(x => x.Name);
        HasMany<Resource, string>(x => x.Resources).AsEntityMap().Element("AccessLevel");
      }
    }
    
    0 讨论(0)
  • 2021-01-01 08:18

    As you've correctly identified in your database schema, this isn't a pure many-to-many relationship - it's two one-to-many relationships as the intermediate table has an attribute (the access level).

    I therefore think your domain is missing an entity - there doesn't appear to be any relationship in your model between a user and the resources they can access.

    How about something like this:

    public class User
    {
        public virtual int Id { get;protected set; }
        public virtual string Name { get;set; }
        public virtual ICollection<UserResource> UserResources { get; set;}
    }
    
    public class UserResource
    {
        public virtual int Id { get; protected set; }
        public virtual User User { get; set;}
        public virtual Resource Resource { get; set;}
        public virtual string AccessLevel { get; set;}
    }
    
    public class Resource
    {
        public virtual int Id { get;protected set; }
        public virtual string Name { get;set; }
    }
    

    And mappings like:

    public class UserMap : ClassMap<User>
    {
        public UserMap()
        {
            Id(x => x.Id);
            Map(x => x.Name);
            HasMany(x => x.UserResource)
                .AsSet()
                .Inverse()
                .Cascade.AllDeleteOrphan();
        }
    }
    
    public class UserResourceMap : ClassMap<UserResource>
    {
        public UserResourceMap()
        {
            Table("UserResourceMap");
            Id(x => x.Id);
            References(x => x.User).Not.Nullable();
            References(x => x.Resource).Not.Nullable();
            Map(x => x.AccessLevel);
        }
    }
    
    public class ResourceMap : ClassMap<Resource>
    {
        public ResourceMap()
        {
            Cache.ReadOnly();
    
            Id(x => x.Id);
            Map(x => x.Name);
        }
    }
    
    0 讨论(0)
提交回复
热议问题