5

我有3个表(多对多的关系)下面的Fluent NHibernate映射有什么问题?

  1. 资源{RESOURCEID,说明}
  2. 角色{角色ID,说明}
  3. 权限{RESOURCEID,角色ID}

我试图在流利的nHibernate中映射上面的表。这是我想要做的。

var aResource = session.Get<Resource>(1); // 2 Roles associated (Role 1 and 2) 
var aRole = session.Get<Role>(1); 
aResource.Remove(aRole); // I try to delete just 1 role from permission. 

但在这里生成的SQL是(这是错误的)

Delete from Permission where ResourceId = 1 
Insert into Permission (ResourceId, RoleId) values (1, 2); 

代替(正道)

Delete from Permission where ResourceId = 1 and RoleId = 1 

为什么NHibernate的这样的表现?映射有什么问题?我甚至尝试过使用Set而不是IList。这是完整的代码。

实体

public class Resource 
{ 
    public virtual string Description { get; set; } 
    public virtual int ResourceId { get; set; } 
    public virtual IList<Role> Roles { get; set; } 

    public Resource() 
    { 
     Roles = new List<Role>(); 
    } 
} 

public class Role 
{ 
    public virtual string Description { get; set; } 
    public virtual int RoleId { get; set; } 
    public virtual IList<Resource> Resources { get; set; } 

    public Role() 
    { 
     Resources = new List<Resource>(); 
    } 
} 

映射这里

// Mapping .. 
public class ResourceMap : ClassMap<Resource> 
{ 
    public ResourceMap() 
    { 
     Id(x => x.ResourceId); 
     Map(x => x.Description); 
     HasManyToMany(x => x.Roles).Table("Permission"); 
    } 
} 

public class RoleMap : ClassMap<Role> 
{ 
    public RoleMap() 
    { 
     Id(x => x.RoleId); 
     Map(x => x.Description); 
     HasManyToMany(x => x.Resources).Table("Permission"); 
    } 
} 

计划

static void Main(string[] args) 
    { 
     var factory = CreateSessionFactory(); 
     using (var session = factory.OpenSession()) 
     { 
      using (var tran = session.BeginTransaction()) 
      { 
       var aResource = session.Get<Resource>(1); 
       var aRole = session.Get<Role>(1); 
       aResource.Remove(aRole); 
       session.Save(a); 
       session.Flush(); 
       tran.Commit(); 
      } 
     } 
    } 
    private static ISessionFactory CreateSessionFactory() 
    { 
     return Fluently.Configure() 
      .Database(MsSqlConfiguration.MsSql2008 
      .ConnectionString("server=(local);database=Store;Integrated Security=SSPI")) 
      .Mappings(m => 
       m.FluentMappings.AddFromAssemblyOf<Program>() 
       .Conventions.Add<CustomForeignKeyConvention>()) 
      .BuildSessionFactory(); 
    } 

    public class CustomForeignKeyConvention : ForeignKeyConvention 
    { 
     protected override string GetKeyName(FluentNHibernate.Member property, Type type) 
     { 
      return property == null ? type.Name + "Id" : property.Name + "Id"; 
     } 
    } 

谢谢, 阿什拉夫。

回答

6

nHibernate认为所有的关系都是双向的,直到你声明父/子。所以你需要“反向”。如果没有这些,则需要两步作为“删除”全部和“重新创建”新的值,特别是“袋”类型(默认)。对于ManyToMany,更改实体集合类型(HashSet/Set)不会影响到“Bag”的映射。它仅适用于HasMany。您需要在地图中专门说“AsSet”。 (IList/ICollection)映射到“Bag”。如果你想要List,你需要在地图上有“AsList”。但是List需要在表格中增加索引列。

// Mapping .. 
public class ResourceMap : ClassMap<Resource> 
{ 
    public ResourceMap() 
    { 
     Id(x => x.ResourceId); 
     Map(x => x.Description); 
     HasManyToMany(x => x.Roles).AsSet().Inverse().Table("Permission"); 
    } 
} 

public class RoleMap : ClassMap<Role> 
{ 
    public RoleMap() 
    { 
     Id(x => x.RoleId); 
     Map(x => x.Description); 
     HasManyToMany(x => x.Resources).AsSet().Cascade.SaveUpdate().Table("Permission"); 
    } 
} 

此外,我会把Fetch.Select()。LazyLoad()for lazyload。

+0

完美。谢谢stoto。因为我使用Resource作为我的主要实体。我需要翻转许多映射。 在ResourceeMap中。 HasManyToMany(x => x.Roles).AsSet()。Cascade.SaveUpdate()。Table(“Permission”); 在RoleMap中。 HasManyToMany(x => x.Resources).AsSet()。Inverse()。Table(“Permission”); – ashraf 2010-03-26 17:15:43

+0

也有人博客关于它。 http://www.codinginstinct.com/2010/03/nhibernate-tip-use-set-for-many-to-many.html – ashraf 2010-03-26 20:13:53