流畅的nhibernate - 具有属性的多对多映射

Mul*_*lki 1 c# nhibernate nhibernate-mapping fluent-nhibernate

我有2个主表,它们通过地图表链接如下

User [UserId,Name]

Resource [ResourceId,Name]

UserResourceMap [UserId,ResourceId,AccessLevel]
Run Code Online (Sandbox Code Playgroud)

具有AccessLevel的Resource和User ClassMap如何作为资源属性?

我的Domain类看起来像这样

public class User
{
    public virtual int UserId { get;protected set; }
    public virtual string Name { get;set; }
}
public class Resource
{
    public virtual int ResourceId { get;protected set; }
    public virtual string Name { get;set; }
    public virtual string AccessLevel { get;set; }//Issue-populate this using fluent
}
Run Code Online (Sandbox Code Playgroud)

如何在下面的代码中使用fluent映射accessLevel属性.

public class UserMap : ClassMap<User>
    {
        public UserMap()
        {
            Table("User");
            Id(x => x.Key);
            Map(x=>x.Name);
        }
    }

public class ResourceMap : ClassMap<Resource>
    {
        public ResourceMap()
        {
            Table("Resource");
            Id(x => x.Key);
            Map(x=>x.Name);//Need some Map Here to make a hasManyToMany Map with attribute
        }
    }
Run Code Online (Sandbox Code Playgroud)

Yhr*_*hrn 7

你的域模型似乎并不符合您的数据库模型 - 资源类有属性ACCESSLEVEL(即每资源一个ACCESSLEVEL),但在DB模式ACCESSLEVEL是在地图上表中的列(即每用户资源一个ACCESSLEVEL关系).

假设DB模型是正确的模型(一种相当简单的)映射方式,那就是引入这样的类.

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; }
}
Run Code Online (Sandbox Code Playgroud)

并以这种方式映射它:

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

如果您想要双向关联,您还可以在User和/或Resource上添加Collection属性,并使用HasMany(...)映射这些属性.Inverse().当然,这种映射会在UserResourceMap表中引入一个新的UserResourceId列(使用由User和Resource组成的复合键可以缓解这一点).

另一种解决方案是添加EntityMap关联.如果关联由User拥有,则它将是Dictionary <Resource,string>属性.这样的事情可能会成功:

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");
  }
}
Run Code Online (Sandbox Code Playgroud)


Ian*_*son 5

正如您在数据库模式中正确识别的那样,这不是纯粹的多对多关系 - 它是两个一对多关系,因为中间表具有属性(访问级别).

因此,我认为您的域名缺少实体 - 您的模型中似乎没有任何关系在用户和他们可以访问的资源之间.

这样的事情怎么样:

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; }
}
Run Code Online (Sandbox Code Playgroud)

和映射如:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)