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