5

Tengo 3 tablas (muchos a muchos)¿Qué pasa con la siguiente asignación fluida de NHibernate?

  1. de Recursos {ResourceId, Descripción}
  2. Rol {RoleId, Descripción}
  3. Permiso {ResourceId, RoleId}

soy tratando de mapear las tablas anteriores en fluent-nHibernate. Esto es lo que intento hacer.

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. 

Pero el SQL generado aquí es (que está mal)

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

En lugar de (manera correcta)

Delete from Permission where ResourceId = 1 and RoleId = 1 

Por qué NHibernate se comportan de esta manera? ¿Qué mal con el mapeo? Incluso intenté con Set en lugar de IList. Aquí está el código completo.

Entidades

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>(); 
    } 
} 

Mapeo Aquí Programa

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

Gracias, Ashraf.

Respuesta

6

nHibernate piensa que toda relación es bidireccional hasta que declare padre/hijo. Por lo tanto, necesita "Inverso". Sin eso, toma dos pasos como "Eliminar" y "Recrear" con el nuevo valor, especialmente el tipo "Bolsa" (valor predeterminado). Para ManyToMany, cambiar el tipo de colección de entidades (HashSet/Set) no afectará la asignación a "Bag". Solo funciona para HasMany. Necesitas decir específicamente "AsSet" en el mapa. (IList/ICollection) se asigna a "Bag". Si quiere Lista, necesita tenerla como "Lista Asignada" en el mapa. Pero List requiere una columna de índice adicional en la tabla.

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

También, me gustaría poner Fetch.Select(). LazyLoad() para lazyload.

+0

Perfecto. Gracias stoto. Dado que estoy usando Resource como mi entidad principal. Necesito cambiar el mapeo de muchos a muchos. En ResourceeMap. HasManyToMany (x => x.Roles) .AsSet(). Cascade.SaveUpdate(). Table ("Permiso"); En RoleMap. HasManyToMany (x => x.Resources). Asset(). Inverse(). Table ("Permiso"); – ashraf

+0

También alguien blog sobre eso también. http://www.codinginstinct.com/2010/03/nhibernate-tip-use-set-for-many-to-many.html – ashraf

Cuestiones relacionadas