简体   繁体   中英

NHibernate Update Not working

I can't get my update to work. The test fails and I do not see any update statements being sent to the database. Can someone tell me what I'm doing wrong?

This is my repository update procedure:

public void UpdateProject(Project proj)
{
    Session.Update(proj);
}

This is the unit test I am trying:

[Test]
public void Can_Update_A_Project()
{
    var project = _projects[0];
    project.Name = "test project";

    repository.UpdateProject(project);

    var fromDb = repository.GetAProject(_projects[0].ID);
    Assert.AreEqual(project.Name, fromDb.Name);        
}

The test always fails. I see the test data being inserted and I see the select for the test.I don't see the update being performed. What am I missing?

Thanks!

There are a couple of things that may be happening.

1) The update is failing and NHibernate is raising an exception that is being swallowed somewhere - that can happen depending on how you've configured things. So in VS make sure all exceptions will cause a break.

2) The update is being cached and not written directly to the DB - you can force data to be written using Repository.Flush();

3) Are you sure _projects[0] has been read from the DB - I'm assuming that's happening in a TestSetup? If not NHibernate won't be aware of that as an object which is under its 'control'.

BTW - It's good practise to read the data you are going to change within the test itself, and then undo that change, resetting the DB to it's original state. In that way your test DB won't be altered by your testing.

BTW2 - In the above test, if project.Name has already been updated once, ie the test has run succesfully. Then next time around the test will suceed even if the update itself fails. A way to avoid this - append a DateTime to the project.Name, don't set it to a fixed value.

Another thing is this: when you save an entity using a session and you load the same entity from the same session using the entity's ID, you will get the same instance that you saved - regardless of whether any inserts or updates have been issued to the database.

That's because of NHibernate's 1st level cache, which is an identity map that belongs to the session.

If you want your test to check what was actually written to the database, you may do it like so:

session.Save(someEntity);
session.Flush(); // forces the entity to be inserted
session.Clear(); // clears the session's identity map, thus
                 // detaching someEntity from the session

var loadedEntity = session.Get<EntityType>(someEntity.Id);

// now you may compare the fields of someEntity and loadedEntity
// to verify that they were actually persisted

ISession.Update in NHibernate does not commit changes to the database. It is used to update transient instances in a different session from the one that was used to retrieve the instance (see here for details). Changes are sent to the database when a session is flushed. By default, sessions operate in FlushOnCommit mode, which means the changes to the objects will be sent to the database when the NHibernate transaction is committed (see here for details on the different flush modes).

try this may be i am wrong but its works

public void UpdateProject(Project proj)
 {
    ISessionFactory SessionFactory;

    ISession session = SessionFactory.OpenSession();

    using (ITransaction transaction = session.BeginTransaction())
    {

      session.Update(proj);
      transaction.Commit();

    }
 }

FlushMode !

I'm maintaining an app I did not write and found out the hard way that even if you use a transaction and call txn.Commit() you still may not see the changes if your NHibernate Session has session.FlushMode = FlushMode.Never .

Very easy to detect. Set a breakpoint and look at session.FlushMode . Or just search all *.cs files for FlushMode.

I recently hit this same issue.

  1. Inserts Worked
  2. Updates Did Not

The issue was a flaw in the coding. Data was checked if the row was changed, then a new entity was mapped, and an update was sent, but nothing happened.

Solution: The actual row had to be queried from the database, then changes in C# applied to that row that was pulled back. Now NHibernate knows the row changed, run save and all worked.

  public void SaveChanges()
  {
      _session.Flush();
      _session.Transaction.Commit();
      _session.BeginTransaction();
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM