Ricevo un errore con NHibernate quando provo a perfrom un'ISession.Delete su qualsiasi tabella con una relazione Uno a Molti.Fluent NHibernate Mapping è impostato su AllDeleteOrphan ma sta ancora tentando di azzerare la chiave esterna nel DB
NHibernate sta tentando di impostare la chiave esterna nella tabella padre nella tabella figlio su null, anziché eliminare semplicemente la riga della tabella figlio.
Ecco il mio 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; }
}
ho set-up le mappature Fluent NHibernate come segue:
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();
}
}
Ho detto NHibernate per Cascade.AllDeleteOrphan()
ma è ancora cercando di impostare il ParentId chiave per null qui è il test che ho impostato:
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);
}
}
Che non funziona o n linea deleteSession.Delete
dopo aver tentato il seguente 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.
Qualcuno sa che cosa ho fatto di sbagliato nelle mie mappature, o sa di un modo per fermare NHibernate di tentare di null l'id della chiave esterna?
Grazie
Dave
Legenda .. grazie .. Ho pensato che Inverse significherebbe che Save fallirebbe, come proverebbe a inserire nel record Child prima che venisse inserito nel record Parent. Ho appena eseguito i test completi di Crud e tutte le cascate funzionano a meraviglia .. grazie :) – CraftyFella
Felice di aiutare. C'è un discreto thread SO sull'uso dell'inverso se aiuta a spiegare meglio: http://stackoverflow.com/questions/1061179/when-to-use-inverse-false-on-nhibernate-hibernate-onetomany-relationships – nkirkes
Che funziona bene! –