Recibo un error con NHibernate cuando intento realizar una ISession.Delete en cualquier tabla con una relación Uno a Muchos.La correspondencia fluida de NHibernate está establecida en AllDeleteOrphan, pero aún está tratando de anular la clave externa en el DB
NHibernate está tratando de establecer la clave externa a la tabla principal en la tabla secundaria como nula, en lugar de simplemente eliminar la fila de la tabla hija.
Aquí es mi dominio:
public class Parent
{
public Parent()
{
_children = new List<Child>();
}
public int Id { get; set; }
public string SimpleString { get; set; }
public DateTime? SimpleDateTime { get; set; }
private IList<Child> _children;
public IEnumerable<Child> Children
{
get { return _children; }
}
public void AddChild(Child child)
{
child.Parent = this;
_children.Add(child);
}
}
public class Child
{
public int Id { get; set; }
public string SimpleString { get; set; }
public DateTime? SimpleDateTime { get; set; }
[JsonIgnore]
public Parent Parent { get; set; }
}
he puesto en marcha las asignaciones Fluido NHibernate de la siguiente manera:
public class ParentMap : ClassMap<Parent>
{
public ParentMap()
{
Not.LazyLoad();
Id(x => x.Id);
Map(x => x.SimpleString);
Map(x => x.SimpleDateTime);
HasMany(x => x.Children)
.Not.LazyLoad()
.KeyColumn("ParentId").Cascade.AllDeleteOrphan()
.Access.ReadOnlyPropertyThroughCamelCaseField(Prefix.Underscore);
}
}
public class ChildMap : ClassMap<Child>
{
public ChildMap()
{
Not.LazyLoad();
Id(x => x.Id);
Map(x => x.SimpleString);
Map(x => x.SimpleDateTime);
References(x => x.Parent).Not.Nullable().Column("ParentId").Cascade.All().Fetch.Join();
}
}
le he dicho a NHibernate a Cascade.AllDeleteOrphan()
pero todavía está tratando de establecer el parentid aquí la clave para anular es la configuración de la prueba I:
public void Delete_GivenTableWithChildren_WillBeDeletedFromDB()
{
int id;
using (var createSession = MsSqlSessionProvider.SessionFactory.OpenSession())
{
var parent = new Parent();
parent.AddChild(new Child { SimpleString = "new child from UI" });
using (var trx = createSession.BeginTransaction())
{
createSession.Save(parent);
trx.Commit();
id = parent.Id;
}
}
using (var firstGetSession = MsSqlSessionProvider.SessionFactory.OpenSession())
{
var result = firstGetSession.Get<Parent>(id);
Assert.IsNotNull(result);
}
using (var deleteSession = MsSqlSessionProvider.SessionFactory.OpenSession())
{
using (var trx = deleteSession.BeginTransaction())
{
deleteSession.Delete("from " + typeof(Parent).Name + " o where o.Id = :Id", id, NHibernateUtil.Int32);
trx.Commit();
}
}
using (var session = MsSqlSessionProvider.SessionFactory.OpenSession())
{
var result = session.Get<Parent>(id);
Assert.IsNull(result);
}
}
¿Qué falla? n la línea deleteSession.Delete
después de intentar el siguiente SQL:
exec sp_executesql N'UPDATE [Child] SET ParentId = null WHERE ParentId = @p0',N'@p0 int',@p0=5
con:
NHibernate.Exceptions.GenericADOException : could not delete collection: [SaveUpdateOrCopyTesting.Parent.Children#5][SQL: UPDATE [Child] SET ParentId = null WHERE ParentId = @p0]
----> System.Data.SqlClient.SqlException : Cannot insert the value NULL into column 'ParentId', table 'SaveUpdateCopyTestingDB.dbo.Child'; column does not allow nulls. UPDATE fails.
The statement has been terminated.
¿Alguien sabe lo que he hecho mal en mis asignaciones, o sabe de una manera de detener NHibernate de intentar anula la identificación de la clave externa?
Gracias
de Dave
Leyenda ... gracias. Pensé que Inverso significaría que Saved fallaría, ya que trataría de insertar en el registro de Child antes de insertarlo en el registro de Parent. Acabo de ejecutar pruebas completas de Crud y todas las cascadas funcionan de maravilla ... gracias :) – CraftyFella
Me alegra ayudar. Hay un hilo SO decente en el uso de la inversa si ayuda a explicar mejor: http://stackoverflow.com/questions/1061179/when-to-use-inverse-false-on-nhibernate-hibernate-onetomany-relationships – nkirkes
Eso funciona ¡multa! –