5

Ho 3 tabelle (relazione molti a molti)Cosa c'è di sbagliato con il seguente Fluent NHibernate Mapping?

  1. Resource {ResourceId, Descrizione}
  2. ruolo {ID ruolo, Descrizione}
  3. Permission {ResourceId, ID ruolo}

Sono cercando di mappare le tabelle sopra in fluente-ibernario. Questo è quello che sto cercando di fare.

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. 

Ma l'SQL generato qui è (che è sbagliato)

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

Invece di (giusta)

Delete from Permission where ResourceId = 1 and RoleId = 1 

Perché NHibernate si comportano in questo modo? Cosa c'è di sbagliato nella mappatura? Ho anche provato con Set invece di IList. Ecco il codice completo.

Enti

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 Qui

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

programma

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

Grazie, Ashraf.

risposta

6

nHibernate ritiene che tutte le relazioni siano bidirezionali finché non si dichiara genitore/figlio. È necessario "Inversa". Senza questo, ci vogliono due passaggi come "Elimina" tutto e "Ricrea" con il nuovo valore, in particolare il tipo "Borsa" (predefinito). Per ManyToMany, il cambiamento del tipo di raccolta delle entità (HashSet/Set) non influirà sulla mappatura su "Bag". Funziona solo per HasMany. Devi dire specificamente "AsSet" sulla mappa. (IList/ICollection) mappa su "Bag". Se vuoi List, devi avere "AsList" sulla mappa. Ma List richiede una colonna indice aggiuntiva nella tabella.

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

Inoltre, vorrei mettere Fetch.Select(). LazyLoad() per lazyload.

+0

Perfetto. Grazie stoto Dal momento che sto usando Resource come mia primaria entità. Devo capovolgere la mappatura da molti a molti. In ResourceeMap. HasManyToMany (x => x.Roles) .AsSet(). Cascade.SaveUpdate(). Table ("Permission"); In RoleMap. HasManyToMany (x => x.Resources) .AsSet(). Inverse(). Table ("Permission"); – ashraf

+0

Anche un blog su questo. http://www.codinginstinct.com/2010/03/nhibernate-tip-use-set-for-many-to-many.html – ashraf