2010-06-06 18 views
20

ich die folgende Störung erhalte, wenn ich versuchte, und meine „Firma“ Einheit in meiner MVC-Anwendung speicherenhibernate: ein anderes Objekt mit dem gleichen Kennungswert wurde bereits mit der Sitzung verknüpft ist: 2, die Einheit:

2, die Einheit: ein anderes Objekt mit dem gleichen Kennungswert wurde bereits mit der Sitzung verknüpft

ich einen IOC-Container

private class EStoreDependencies : NinjectModule 
    { 
     public override void Load() 
     { 

      Bind<ICompanyRepository>().To<CompanyRepository>().WithConstructorArgument("session", 
                         NHibernateHelper.OpenSession()); 
     } 
    } 

Mein CompanyRepository bin mit

public class CompanyRepository : ICompanyRepository 
{ 
    private ISession _session; 

    public CompanyRepository(ISession session) 
    { 
     _session = session; 
    }  

    public void Update(Company company) 
    { 

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

      _session.Update(company); 
      transaction.Commit(); 
     } 
    } 

}

Und Session Helper

public class NHibernateHelper 
{ 
    private static ISessionFactory _sessionFactory; 
    const string SessionKey = "MySession"; 


    private static ISessionFactory SessionFactory 
    { 
     get 
     { 
      if (_sessionFactory == null) 
      { 
       var configuration = new Configuration(); 
       configuration.Configure(); 
       configuration.AddAssembly(typeof(UserProfile).Assembly); 
       configuration.SetProperty(NHibernate.Cfg.Environment.ConnectionStringName, 
              System.Environment.MachineName); 
       _sessionFactory = configuration.BuildSessionFactory(); 
      } 
      return _sessionFactory; 
     } 
    } 

    public static ISession OpenSession() 
    { 
     var context = HttpContext.Current; 
     //.GetCurrentSession() 

     if (context != null && context.Items.Contains(SessionKey)) 
     { 
      //Return already open ISession 
      return (ISession)context.Items[SessionKey]; 
     } 
     else 
     { 
      //Create new ISession and store in HttpContext 
      var newSession = SessionFactory.OpenSession(); 
      if (context != null) 
       context.Items[SessionKey] = newSession; 

      return newSession; 
     } 
    } 
} 

Meine MVC Aktion

[HttpPost] 
    public ActionResult Edit(EStore.Domain.Model.Company company) 
    { 

      if (company.Id > 0) 
      { 

       _companyRepository.Update(company); 
       _statusResponses.Add(StatusResponseHelper.Create(Constants 
        .RecordUpdated(), StatusResponseLookup.Success)); 
      } 
      else 
      { 
       company.CreatedByUserId = currentUserId; 
       _companyRepository.Add(company); 
      } 


     var viewModel = EditViewModel(company.Id, _statusResponses); 
     return View("Edit", viewModel); 
    } 
+0

Können Sie das Problem in einem Komponententest reproduzieren? –

Antwort

32

Ich weiß, das ist ein bisschen spät und Sie vielleicht schon gefunden, die Lösung, aber vielleicht andere könnte davon profitieren ...

Dies Der Fehler wird von nHibernate ausgelöst, wenn Sie eine Instanz einer Entität aktualisieren, die im Cache gespeichert ist. Im Grunde speichert nHibernate Ihre Objekte im Cache, sobald Sie sie geladen haben, sodass die nächsten Aufrufe sie aus dem Cache abrufen würden. Wenn Sie eine Instanz aktualisieren, die im Cache vorhanden ist, löst nHibernate diesen Fehler aus, andernfalls kann es zu fehlerhaften Lesevorgängen und Konflikten beim Laden der alten Kopie des Objekts kommen.

public ActionResult Edit(EStore.Domain.Model.Company company) 
{ 

     if (company.Id > 0) 
     { 
      **ISession.Evict(company);** 
      _companyRepository.Update(company); 

hoffte, das hilft: die Evict Methode wie Um dies zu umgehen, müssen Sie das Objekt aus dem Cache entfernen.

+2

Hallo Dank für das Beantworten, Eigentlich eine schlecht entworfene Frage von mir. Es stellt sich heraus, dass eine meiner Entitäten nicht dieselbe Sitzung verwendet, die mit Ihrer obigen Erklärung übereinstimmt. – frosty

+9

Das ist ein Hack. Ich wette, das Problem ist, dass Sie die vorherige Sitzung nicht richtig löschen und schließen. –

+1

Das Problem scheint zu sein, dass NHibernate das neu erstellte Objekt nicht erkennt (außerhalb der NHibernate-Sitzung). Siehe meine Antwort. – lko

1

für mehr agrgessive Art und Weise können Sie die Clear() Methode verwenden

+4

Dadurch werden alle ausstehenden Transaktionsänderungen gelöscht. – gwin003

3

Eine mögliche Lösung dieses Problems ist das Objekt aus der Datenbank zu lesen, kopieren Sie die Felder auf das Objekt, und speichern. Die NHibernate-Sitzung weiß nichts über das eingehende Objekt, das von einem MVC Model Binder instanziiert wurde.

In bestimmten Fällen ist das gesamte Objekt möglicherweise nicht sichtbar oder wird an das View/ViewModel übergeben. Beim Speichern sollte es zuerst von NHibernate gelesen, dann aktualisiert und gespeichert werden.

Company cOrig = _companyRepository.Get(company.Id); 
cOrig.PropertyToUpdate = company.PropertyToUpdate; 
... // Copy the properties to be updated. 
// Save the freshly retrieved object! 
// Not the new object coming from the View which NHibernate Session knows nothing about. 
_companyRepository.Update(cOrig); 

Diese Analyse erfordert/Abbildung der Ansichtsmodell/Klasse Eigenschaften der Domain Model/Klasse, aber in vielen Fällen Sie müssen nicht präsentieren sie alle in der Ansicht aktualisiert werden, so dass Sie es trotzdem tun müssten (Teilweise leere Objekte können nicht über alten Objekten gespeichert werden).

8

Ich versuchte @ claitonlovatojr's Hack, aber ich konnte den Fehler noch nicht behandeln.

Alles, was ich in meinem Fall tun musste, war es, meinen ISession.Update(obj) Anruf zu ISession.Merge(obj) zu ersetzen.

In Ihrem Repository ändern:

public void Update(Company company) 
{ 
    using (ITransaction transaction = _session.BeginTransaction()) 
    { 
     //_session.Update(company); 
     _session.Merge(company); // <-- this 
     transaction.Commit(); 
    } 
} 

Auch für weitere Informationen siehe this answer.

Verwandte Themen