NHibernate will not let me inject a model into a session if it was part of a failed transaction in that session

Why can't I just insert the model after I get an error from the database when I try to insert it the first time:

Report report = null;
using (var session = SessionFactory.OpenSession()) {
    try {
        using (var transaction = session.BeginTransaction()) {
            report = new Report();
            session.SaveOrUpdate(report);//Exception: Name field required
            transaction.Commit();
        }
    }
    catch { }

    try {
        using (var transaction = session.BeginTransaction()) {
            report.Name = "theName";
            session.SaveOrUpdate(report);

            //Causes Exception:
            //Row was updated or deleted by another transaction (or unsaved-value 
            //mapping was incorrect): [ReportViewer.DataAccess.Models.Report#22]                          
            transaction.Commit();
        }
    }
    catch { }
}

      

But when I update an existing model and get an error, I can make my fixes (set the name in this case) and just try to update again:

Report report = null;
using (var session = SessionFactory.OpenSession()) {
    using (var transaction = session.BeginTransaction()) {
        report = new Report();
        report.Name = "theName";
        session.SaveOrUpdate(report);
        transaction.Commit();
    }
}
using (var session = SessionFactory.OpenSession()) {

    //get entity saved from previous session
    report = session.Get<Report>(report.Id);

    try {
        using (var transaction = session.BeginTransaction()) {
            report.Name = null;
            session.SaveOrUpdate(report);//Exception: Name field required
            transaction.Commit();
        }
    }
    catch { }

    try {
        using (var transaction = session.BeginTransaction()) {

            //updates and does not give an error
            report.Name = "theName";
            session.SaveOrUpdate(report);
            transaction.Commit();
        }
    }
    catch { }
}

      

+3


source to share


2 answers


As Oscar said, you should drop your NHibernate session after an exception is thrown. However, the reason the insert fails is because you have already made the report persistent by calling SaveOrUpdate

on it (you should use here Save

). When you call SaveOrUpdate

again on the same instance, NHibernate will throw an exception because the object is already persistent. Rewriting the code like this will probably allow a successor to be inserted (but this is not recommended):

try {
    using (var transaction = session.BeginTransaction()) {
        report.Name = "theName";                   
        transaction.Commit();
    }
}

      



In the update example, the call has SaveOrUpdate

no effect because the object became persistent when NHibernate loaded it. Understanding NHibernate instance states and how to work with persistent objects is fundamental and widely misunderstood.

It is much better to check your objects before storing them in the database.

+2


source


When a database-triggered event occurs, the NHibernate session must be closed (deleted). Once thrown, the exception cannot be consistent (internally or with the DB state).



See the chapter on exception handling in NHibernate reference .

+4


source







All Articles