2012-07-13 12 views
8

Tengo un mapeo unidireccional muy simple. ver más abajo:NHibernate todavía publica la actualización después de la inserción

public ContactMap() 
    { 
     Id(x => x.Id).GeneratedBy.Assigned(); 
     Map(x => x.Name); 
     References(x => x.Device); 
     HasMany(x => x.Numbers) 
      .Not.Inverse() 
      .Not.KeyNullable() 
      .Cascade.AllDeleteOrphan() 
      .Not.LazyLoad() 
      .Fetch.Subselect(); 
     Table("Contacts"); 
    } 


    public PhoneNumberMap() 
    { 
     Id(x => x.Id).GeneratedBy.Native(); 
     Map(x => x.Number); 
     Table("ContactNumbers"); 
    } 

De acuerdo con esta post después nhibernate 3 y superior, tecla que no anulable ajuste debe solucionar el problema de inserción-actualización (El problema cuando NHibernate emite un inserto con clave externa configurado en nulo y luego una actualizar para actualizar la clave externa para corregir el valor), pero este no es el caso para mí. Cuando me puse la llave como no anulable, NHibernate emite una instrucción de inserción correcta

INSERT INTO ContactNumbers 
      (Number, 
      ContactId) 
VALUES  ('(212) 121-212' /* @p0 */, 
      10 /* @p1 */); 

Como se puede ver, se inserta el campo ContactId, pero después de eso, todavía emite instrucción de actualización

UPDATE ContactNumbers 
SET ContactId = 10 /* @p0 */ 
WHERE Id = 34 /* @p1 */ 

Así que para aclarar el problema NHibernate inserta la fila de contacto con la clave externa asignada correctamente y luego de eso, emite una declaración de actualización para actualizar la clave externa (ContactId) que es redundante.

¿Cómo puedo deshacerme de esta declaración de actualización redundante? Gracias.

Por cierto, estoy usando la última versión de NHibernate y Fluidez NHibernate. La base de datos es SQLite

Respuesta

20

Tienes que configurar "updatable"=false en tu llave para evitar actualizaciones.

public ContactMap() 
{ 
    Id(x => x.Id).GeneratedBy.Assigned(); 
    Map(x => x.Name); 
    References(x => x.Device); 
    HasMany(x => x.Numbers) 
     .Not.Inverse() 
     .Not.KeyNullable() 
     .Not.KeyUpdate() // HERE IT IS 
     .Cascade.AllDeleteOrphan() 
     .Not.LazyLoad() 
     .Fetch.Subselect(); 
    Table("Contacts"); 
} 
+1

Cuando todas las esperanzas desaparecieron, llegaste: D. Simple, claro y funciona a la perfección. Incluso reemplazó la operación de Actualización/Eliminación con una sola eliminación. Maldita sea, no sabes cuán agradecido estoy. Este fue un tema importante que muchos desconocen. Gracias hazzik. – Davita

+1

Sí, deberíamos actualizar nuestra documentación, pero es un trabajo enorme y aburrido :( – hazzik

+1

Entiendo, gracias a Dios tenemos SO :-) – Davita

3

No sé si realmente puedes deshacerte de ella.

Intente usar otro generador de identificación como nativo. Obliga a NH a insertar el registro solo para obtener el id. La identificación se usa para cada entidad en la sesión, por lo que no puede hacer la inserción más tarde. Puede ser caso de actualizaciones posteriores. Use hi-lo o algo similar.

Editar

Por qué no está usando un componente en este caso? No necesita asignar el número de teléfono por separado, si se trata solo de un número. Algo como esto (no soy un usuario HNF, por lo que puede ser malo):

public ContactMap() 
{ 
    Id(x => x.Id).GeneratedBy.Assigned(); 
    Map(x => x.Name); 
    References(x => x.Device); 
    HasMany(x => x.Numbers) 
     .Not.Inverse() 
     .Not.KeyNullable() 
     .Cascade.AllDeleteOrphan() 
     .Not.LazyLoad() 
     .Fetch.Subselect() 
     .Component(c => 
     { 
      Map(x => x.Number); 
     }) 
     .Table("ContactNumbers"); 
    Table("Contacts"); 
} 
+0

Lo siento, no pude entender lo que quieres decir. ¿Podrías elaborar un poco por favor? :) – Davita

+0

Cambié la generación de ID a HiLo, pero no ayudó. – Davita

+0

El componente no funcionará aquí, tiene una relación de uno a muchos con Números. – Davita

4

No se puede partir de 3.2.0 beta.

en beta v3.2.0 una mejora a uno-a-muchos introducido esta anomalía a Unidireccional relaciones uno-a-muchos (en realidad no estoy seguro de si anormaly es lo que llamarían esto).

Antes de 3.2 necesitarás configurar la clave externa para permitir nulos para que este tipo de relación funcione. Por lo tanto, ignoraría el hecho de que esto sucede y simplemente me iré con eso. De lo contrario, tendrá que cambiarlo a una relación totalmente bidireccional.

  • [NH-941] - Uno-Muchos Exigir anulables claves externas

Release notes o JIRA issue

edición también la respuesta a la entrada que apunta a es reparar save null-save-update en lugar de corregir la actualización adicional

+0

Maldita sea, el soporte de Nhibernate para asociaciones unidireccionales apesta. Esperaré por otras respuestas y aceptaré las tuyas si no aparece nada bueno. Mientras tanto, comprobaré primero el código EF + :( – Davita

3

Intente establecer inverse en true en la asignación y la asignación de la relación en el código.

Inverse significa que el niño es responsable de mantener la identificación del padre.

p. Ej.

var contact = new Contact(); 
var phoneNumber = new PhoneNumber(); 
phoneNumber.Contact = contact; 

De esta manera, cuando se hace el inserto para el registro Fax, NH puede insertar el ContactId sin tener que hacer una actualización independiente.

Eso es lo que solía hacer en el NH 2, asumiría el comportamiento sigue funcionando de la misma en 3.

+0

No quiero hacer lo contrario. Esa es la idea. Quiero que Contact sea responsable de la persistencia de los números. – Davita

1

Es lo que dijo Trevor Pilley. Use inverse="true". Si elige no tener inverse="true", esta es la consecuencia de esa elección. No puedes tenerlo de las dos maneras.

Cuestiones relacionadas