studio - Cómo salvar a un niño con una identificación asignada en nhibernate
nhibernate vs entity framework (3)
Calling session.SaveOrUpdate (childObject) debe resolver el problema.
Tengo dos clases:
public class Parent
{
public virtual long? ID { get; set; } // native
public virtual IList<Child> Children { get; set; }
public virtual string Name { get; set; }
}
public class Child
{
public virtual long ID { get; set; } // assigned
public virtual string Name { get; set; }
}
Creando y salvando padres e hijos:
child = new Child() { ID = 1, Name = "SomeName" };
parent = new Parent() { Children = new List() { child } };
session.Save(parent);
Lo que me da:
NHibernate.StaleStateException: recuento de filas inesperado: 0; esperado: 1.
Creo que el problema es con la identificación asignada en el niño. Dado que tiene una identificación, NHibernate cree que se ha guardado anteriormente, lo que no es el caso.
El SQL generado (recortado y renombrado) es:
NHibernate: select child0_.ID as child1_1_, child0_.NAME as NAME1_, child0_.PARENT_ID as COMMAND7_1_, from CHILD child0_
NHibernate: select parent0_.PARENT_ID as parent1_10_
NHibernate: select parent0_.PARENT_ID as parent1_10_, parent0_.NAME as parent2_10_ from PARENT parent0_
NHibernate: UPDATE CHILD SET PARENT_ID = @p0 WHERE CHILD_ID = @p1;@p0 = 2, @p1 = 1
Mapeo de archivos:
<class name="MyNamespace.Child" table="CHILD">
<id name="ID" column="CHILD_ID" type="System.Int64">
<generator class="assigned"></generator>
</id>
<property name="Name" column="NAME"></property>
</class>
<class name="MyNamespace.Parent" table="PARENT">
<id name="ID" column="PARENT_ID" type="System.Int64">
<generator class="native"></generator>
</id>
<property name="Name" column="NAME"></property>
<bag name="Children">
<key column="PARENT_ID"></key>
<one-to-many class="MyNamespace.Child"></one-to-many>
</bag>
</class>
Mientras buscaba en google, encontré una etiqueta de versión que puede ser una solución, pero no tengo un campo persistente para usar como versión. En este caso, ¿cómo puedo guardar (insertar) un hijo con un ID asignado y su padre?
Cuando se conecta en cascada de un padre a un hijo, NHibernate usa el método SaveOrUpdate. Tiene razón en que NHibernate necesita alguna forma de determinar si debe realizar una inserción o una actualización. Observará tres campos diferentes para un valor no guardado para determinar si la entidad es nueva.
- Carné de identidad
- Versión
- Marca de tiempo
Con una identificación asignada, necesitará un campo Versión o Marca de tiempo para indicar que la entidad es nueva.
Una alternativa sería llamar a Save () en los niños explícitamente.
No estoy seguro al 100% de si este es el mismo problema que está teniendo, pero mi base de datos tiene una identificación (ugh) asignada al 100% y tuve que crear un Interceptor que rastreaba si un niño es persistente o no en las cascadas trabajar.
El código es cortar / pegar (por lo que tiene nombres tontos ... ¡Al principio no lo entendí al 100%!), E inicialmente obtuve el 90% de la documentación en línea (que no puedo encontrar a través de google) ahora ... lo siento):
La clase base que coloca en el objeto que tiene un ID asignado que desea conectar en cascada:
public class Persistent
{
private bool _saved = false;
public virtual void OnSave()
{
_saved = true;
}
public virtual void OnLoad()
{
_saved = true;
}
public virtual bool IsSaved
{
get { return _saved; }
}
}
El interceptor que agregas a la sesión:
public class TrackingNumberInterceptor : EmptyInterceptor
{
public override bool? IsTransient(object entity)
{
if (entity is Persistent)
{
return !((Persistent)entity).IsSaved;
}
else
{
return null;
}
}
public override bool OnLoad(object entity, object id, object[] state, string[] propertyNames, IType[] types)
{
if (entity is Persistent) ((Persistent)entity).OnLoad();
return false;
}
public override bool OnSave(object entity, object id, object[] state, string[] propertyNames, IType[] types)
{
if (entity is Persistent) ((Persistent)entity).OnSave();
return false;
}
}
Básicamente, la idea es que, dado que NHibernate no sabe si una entidad de identificación asignada se conserva o no, se realiza un seguimiento de la misma.
Por defecto, el objeto comienza con persistido (_saved) en falso. Cuando la entidad está cargada o guardada por NHibernate, el activador establece el indicador de objetos persistentes (guardados) en verdadero.
Entonces, para un artículo nuevo que no se conserva, comienza en falso y permanece falso porque NHibernate nunca lo ha guardado ni cargado. Cuando NHibernate verifica si el niño es transitorio, el activador responde que es transitorio, y ocurre una operación de guardado que marca al niño como persistente. Además, ahora cualquier uso futuro requerirá una carga que nuevamente lo marca como persistente.