5

Ich habe 3 Tabellen (viele zu viele Beziehung)Was ist falsch an der folgenden Fluent NHibernate Mapping?

  1. Ressource {ResourceId, Beschreibung}
  2. Rolle {RoleId, Beschreibung}
  3. Permission {ResourceId, RoleId}

Ich bin versuchen, über Tabellen in fließendem nHibernate abzubilden. Das ist es was ich versuche zu tun.

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. 

Aber die SQL hier erzeugt wird, statt (richtig) (was falsch ist)

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

Delete from Permission where ResourceId = 1 and RoleId = 1 

Warum nHibernate wie diese verhalten? Was stimmt nicht mit dem Mapping? Ich habe es sogar mit Set anstelle von IList versucht. Hier ist der vollständige Code.

Entities

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 Hier

// 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"); 
    } 
} 

Programm

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"; 
     } 
    } 

Danke, Ashraf.

Antwort

6

nHibernate denkt, dass alle Beziehungen bidirektional sind, bis Sie Eltern/Kind deklarieren. So brauchen Sie "Inverse". Ohne dies, es dauert zwei Schritte wie "Löschen" alle und "neu erstellen" mit dem neuen Wert, vor allem "Tasche" Typ (Standard). Bei ManyToMany wirkt sich die Änderung des Entity Collection-Typs (HashSet/Set) nicht auf die Zuordnung zu "Bag" aus. Sie funktioniert nur für HasMany. Sie müssen in der Karte ausdrücklich "AsSet" sagen. (IList/ICollection) entspricht "Tasche". Wenn Sie Liste möchten, müssen Sie es "AsList" in der Karte haben. Aber List benötigt eine zusätzliche Indexspalte in der Tabelle.

// 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"); 
    } 
} 

Außerdem würde ich Fetch.Select(). LazyLoad() für lazyload setzen.

+0

Perfekt. Danke, stoto. Da ich Ressource als meine primäre Entität verwende. Ich muss das viele zu viele Mapping umdrehen. In ResourceeMap. HasManyToMany (x => x.Roles) .AsSet(). Cascade.SaveUpdate(). Tabelle ("Permission"); In RoleMap. HasManyToMany (x => x.Resources) .AsSet(). Inverse(). Tabelle ("Permission"); – ashraf

+0

Auch jemand bloggt darüber. http://www.codinginstinct.com/2010/03/nhibernate-tip-use-set-for-many-to-many.html – ashraf