2011-04-27 10 views
11

tengo 3 tablas en mi base de datos:nhibernate "en cascada =" all-delete-orphan" error

  1. Proyectos (id, nombre)
  2. Etiquetas (id, nombre)
  3. ProjectsTagss (id, projectId, TagID)

Como se puede ver los ProjectsTags mesa es una mesa de bridge

aquí es mi mapeo fluidez nhibernate

ProjectMap.cs:

Map(x => x.Name).Not.Nullable(); 
HasMany(x => x.ProjectsTags).AsBag().Inverse() 
    .Cascade.AllDeleteOrphan().Fetch.Select().BatchSize(80); 

ProjectsTagsMap.cs:

References(x => x.Project).Not.Nullable(); 
References(x => x.Tag).Not.Nullable(); 

TagMap.cs:

Map(x => x.Name).Not.Nullable(); 

Como puede ver, históricamente no tenía la tabla de etiquetas vinculada a otra cosa. Ahora necesito generar un informe para mostrar la etiqueta y con qué frecuencia se utiliza esa etiqueta, así que necesito unirme de Tag a ProjectsTag. He intentado añadir esta línea en el tagsmap:

HasMany(x => x.ProjectsTags).AsBag().Inverse() 
    .Cascade.AllDeleteOrphan().Fetch.Select().BatchSize(80); 

, pero cuando voy a actualizar el nombre de un objeto etiqueta y comprometerse, me sale este error:

Una colección con cascada = "all-eliminar -orphan "ya no estaba referenciado por la entidad propietaria instancia

alguien puede ver algo mal con lo que agregué que estaría causando esta excepción nhibernate cuando simplemente actualizo la tabla de etiquetas. Una vez más mi objetivo es ser capaz de hacer algo como:

Tag.ProjectTags.Count(); 

Aquí hay un código adicional solicitada:

mi etiqueta Clase:

public class Tag 
{ 
    public virtual IList<ProjectTag> ProjectTags { get; set; } 
    public virtual string Name { get; set; } 
    public virtual string Description { get; set; } 
} 
+1

Muéstranos el código en el que actualizar las etiquetas. Y por favor escriba un título significativo que exprese la pregunta. –

+0

@Stefan Steinegger - título actualizado para reflejar el error – leora

+1

El error ocurre cuando elimina un elemento de la lista y lo vuelve a utilizar en otra lista. Entonces, por favor muéstranos el código que escribiste para actualizar los datos. –

Respuesta

7

Si bien no se modifica una colección, NH todavía puede pensar que se trata. Algo como esto podría ser causado por una actualización fantasma. Del libro de cocina NHibernate 3.0, Jason Dentler (página 184): "Como parte de la verificación automática sucia, NHibernate compara el estado original de una entidad con . Una entidad que no se ha modificado puede actualizarse innecesariamente porque una conversión de tipo causó esta comparación fallar ".

actualización Fantasma de colección puede ser causada por el código que se parece a esto:

public class Tag 
{ 
    private IList<ProjectTag> projectsTags; 

    public virtual IEnumerable<ProjectTag> ProjectsTags 
    { 
     get 
     { 
      return new ReadOnlyCollection<ProjectTag>(projectsTags); 
     } 

     set 
     { 
      projectsTags = (IList<ProjectTag>)value; 
     } 
    } 
} 

ProjectsTags propiedad devuelve la colección de envoltura de sólo lectura, por lo que el código de cliente no puede agregar o quitar elementos a/de la colección.

El error aparecerá incluso cuando no se cambia el nombre de una etiqueta:

private void GhostTagUpdate(int id) 
{ 
    using (var session = OpenSession()) 
    { 
     using (var transaction = session.BeginTransaction()) 
     { 
      var tag = session.Get<Tag>(id); 

      transaction.Commit(); 
     } 
    } 
} 

colección ProjectsTags debe correlacionarse con la estrategia de acceso CamelCaseField para evitar fantasma actualización:

HasMany(x => x.ProjectsTags) 
    .Access.CamelCaseField() 
    .AsBag().Inverse().Cascade.AllDeleteOrphan().Fetch.Select().BatchSize(80); 

fin ...

Su asociación parece ser diabólicamente compleja. Si la tabla ProjectsTags debería contener solamente Identificación de la etiqueta y la identificación de proyectos, entonces sería más fácil de usar FNH muchos-a-muchos mapeo bidireccional:

public class Tag2Map : ClassMap<Tag2> 
{ 
    public Tag2Map() 
    { 
     Id(x => x.Id); 
     Map(x => x.Name); 
     HasManyToMany(x => x.Projects) 
      .AsBag() 
      .Cascade.None() 
      .Table("ProjectsTags") 
      .ParentKeyColumn("TagId") 
      .ChildKeyColumn("ProjectId"); 
    } 
} 

public class Project2Map : ClassMap<Project2> 
{ 
    public Project2Map() 
    { 
     Id(x => x.Id); 
     Map(x => x.Name); 
     HasManyToMany(x => x.Tags) 
      .AsBag() 
      .Cascade.None() 
      .Inverse() 
      .Table("ProjectsTags") 
      .ParentKeyColumn("ProjectId") 
      .ChildKeyColumn("TagId"); 
    } 
} 

Ahora no hay necesidad de ProjectTag entidad en el modelo. El recuento de cuántas veces se utiliza la etiqueta utilizada se puede recuperar de dos maneras:

Forma directa: tag.Projects.Count() - pero recupera todos los proyectos de la base de datos.

forma de consulta:

var tag = session.Get<Tag2>(tagId); 
var count = session.Query<Project2>().Where(x => x.Tags.Contains(tag)).Count(); 
16

En algún lugar de su código, que debe tener eliminó la referencia de la colección original en su dominio de Proyecto. Sospecho que su código es el siguiente:

var project = Session.Get<Project>(); 
project.ProjectsTags = new List<ProjectsTags> { someProjectsTagsInstance }; 
Session.Save(project); 

Si este es el caso, debe hacerse lo siguiente:

var project = Session.Get<Project>(); 
project.ProjectsTags.Clear(); 
project.ProjectsTags.Add(someProjectsTagsInstance); 
Session.Save(project); 
+0

Sí, este fue nuestro problema. ¿Alguna idea de lo que podría estar causando? – VoodooChild

+0

Lo que hace que NHibernate "tome el control" de la lista 'ProjectTags' y rastrea todo lo que contiene. Al reemplazar toda la lista en la entidad propietaria, desconectas esta lista rastreada, pero aún se realiza un seguimiento y, al guardarla, NHibernate no sabe qué hacer con todos los objetos que contiene. – codekaizen

Cuestiones relacionadas