Wie behandeln die Aktualisierung von Entitäten. NHibernate + ASP.NET MVC
Kann ich nicht aktualisieren, die zuvor erstellte Einheit. Ich bin immer ein StaleObjectException
Ausnahme mit der Meldung:
Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [Project.DomainLayer.Entities.Employee#00000000-0000-0000-0000-000000000000]
Teile ich nicht den update-Prozess mit niemandem. Was ist das problem?
Data Access /DI
public class DataAccessModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
this.Bind<ISessionFactory>()
.ToMethod(c => new Configuration().Configure().BuildSessionFactory())
.InSingletonScope();
this.Bind<ISession>()
.ToMethod(ctx => ctx.Kernel.TryGet<ISessionFactory>().OpenSession())
.InRequestScope();
this.Bind(typeof(IRepository<>)).To(typeof(Repository<>))
.InRequestScope();
}
}
Data Access /Zuordnungen
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Project.DomainLayer" namespace="Project.DomainLayer.Entities">
<class name="Employee" optimistic-lock="version">
<id name="ID" column="EmployeeID" unsaved-value="00000000-0000-0000-0000-000000000000">
<generator class="guid.comb" />
</id>
<version name="Version" type="Int32" column="Version" />
<!-- properties -->
<property name="EmployeeNumber" />
<!-- ... -->
<property name="PassportRegistredOn" not-null="true" />
<!-- sets -->
<set name="AttachedInformation" cascade="all">
<key column="EmployeeID" />
<element column="Attachment" />
</set>
<set name="TravelVouchers" cascade="all">
<key column="EmployeeID" />
<one-to-many class="TravelVoucher" />
</set>
</class>
</hibernate-mapping>
Data Access /Repository
public class Repository<T> : IRepository<T> where T : AbstractEntity<T>, IAggregateRoot
{
private ISession session;
public Repository(ISession session)
{
this.session = session;
}
//other methods are omitted
public void Update(T entity)
{
using(var transaction = this.session.BeginTransaction())
{
this.session.Update(entity);
transaction.Commit();
}
}
public void Update(Guid id)
{
using(var transaction = this.session.BeginTransaction())
{
this.session.Update(this.session.Load<T>(id));
transaction.Commit();
}
}
}
Im inneren ein Controller
public class EmployeeController : Controller
{
private IRepository<Employee> repository;
public EmployeeController(IRepository<Employee> repository)
{
this.repository = repository;
}
public ActionResult Edit(Guid id)
{
var e = repository.Load(id);
return View(e);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Employee employee)
{
if(ModelState.IsValid)
{
repository.Update(employee);
return RedirectToAction("Deatils", "Employee", new { id = employee.ID });
}
else
{
return View(employee);
}
}
}
Wie aktualisiere ich meine Einheiten?
Danke!
BEARBEITEN
Also ich habe unsaved-value="{Guid.Empty goes here}"
meinem markup. Außerdem habe ich versucht zu tun, die nächste Sache:
public void Update(T entity)
{
using(var transaction = this.session.BeginTransaction())
{
try
{
this.session.Update(entity);
transaction.Commit();
}
catch(StaleObjectStateException ex)
{
try
{
session.Merge(entity);
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
}
}
Und das gibt mir den gleichen Effekt.. ich meine transaction.Commit();
nach Merge
gibt die gleiche Ausnahme.
Auch ich Frage mich, sollte ich aussetzen, versteckte Eingabe, die Person ID
auf die Edit
?
BEARBEITEN
So Entität wirklich löst. Wenn es geht um die Steuerung der ID
gleich Guid.Empty
. Wie kann ich das umgehen, Merge
oder Reattach
?
InformationsquelleAutor lexeme | 2012-03-14
Du musst angemeldet sein, um einen Kommentar abzugeben.
Gibt es zwei Szenarien, die Sie ausführen können, in Anbetracht Ihrer code-Muster.
Konnte Sie abrufen, das Objekt aus der db mit
ISession.Get()
werden kann, gefolgt von einem Wechsel/update auf das abgerufene Objekt. Für diese änderung wirksam zu sein, alles, was Sie tun müssen, ist, Spülen Sie die Sitzung oder commit für die Transaktion wie Nhibernate verfolgen alle änderungen automatisch für Sie.Haben Sie eine transiente Instanz, ein Objekt, das nicht im Zusammenhang mit den
ISession
im Kontext, von der aus Sie aktualisieren möchten. In diesem Fall, aus meiner Erfahrung, die beste Vorgehensweise ist, umISession.Get()
das Objekt und machen Sie die entsprechenden änderungen an dem Objekt, das Sie nur abrufen. (in der Regel Ihre view-Modell unterscheidet sich von Ihr domain-Modell als auch, nicht mischen) Dieses Muster ist nachfolgend dargestellt. Es arbeitet die ganze Zeit. Stellen Sie sicher auchISession.SaveOrUpdate()
.Beachten Sie auch, dass Ihr controller ist wahrscheinlich instanziiert auf einer pro-Anfrage-basis, damit die Lebensdauer Ihrer
ISession
nicht über mehrere Aufrufe der verschiedenen Methoden, die Sie in Ihrem controller. In anderen Worten, jede Methode ist fast immer die Arbeit im Rahmen eines neuenISession
(unit of work).employee
mitid == Guid.Empty
?Wenn Sie ein update für das Objekt, die ID sollte nicht Guid.Leer. Nur, wenn Sie in den Prozess des erstellen/speichern der neuen Sache wird. Die ID kann entweder erzeugt werden, die Ihre app verwenden oder die Datenbank. Siehe nhibernate Dokumentation
Schauen Sie auf meine Antwort unten. Das ist die Art, wie es funktioniert. Ratschläge werden geschätzt.
Super Antwort, nach shevchyk Antwort, ich denke du meinst "Sie haben eine
detached
Instanz" stackoverflow.com/questions/161224/...InformationsquelleAutor Newbie
Ihre Logik ist nicht gut, denn Sie nutzen domain-Modell wie Mitarbeiter als ViewModel. Best practice ist die Verwendung CreateEmploeeViewModel und EditEmployeeViewModel und separate Domain-Logik und View-Modell-Logik.
Zum Beispiel:
Konvertieren von Mitarbeiter zu ViewModel ich lieber yo verwenden Automapper.
Also controller-Aktionen werden, sieht wie folgt aus:
In diesem Fall NHibernate weiß, dass Sie ein update für Mitarbeiter, und Sie können nicht entfernen Sie einige Eigenschaften, die nicht in Ihre Ansicht.
obwohl Sie Recht haben, domainmodel vs viewmodel ist gut. Aber nicht jede Beziehung mit die Frage.
Wenn man sich anwser Sie können sehen, was ist die Lösung. Option 2.
InformationsquelleAutor Ivan Korytin
Ich glaube, dass Ihre Mitarbeiter-Objekt geworden ist, was NHibernate Anrufe "detached" zwischen GET und POST der Edit-action-Methoden. Finden Sie die NHibernate Dokumentation zu diesem Thema für weitere details und einige Lösungen. In der Tat, der link beschreibt den genauen GET-POST-Szenario, das Sie zu sein scheinen mit.
Möglicherweise müssen Sie fügen Sie der Mitarbeiter-Objekt und/oder geben Sie die "nicht gespeicherten Wert" als Firo vorgeschlagen, so dass NHibernate weiß ein Mitarbeiter mit der ID Guid.Leer hat nicht gespeichert worden ist, um die Datenbank noch. Ansonsten, wie Firo vorgeschlagen, NHibernate sieht Guid.Leer wie ein Gültiger Personalausweis, und denkt, dass das Objekt bereits in der Datenbank gespeichert, sondern die Sitzung, in der es abgerufen wurde wurde verworfen (daher, das Objekt zu "detached").
Hoffe, das hilft.
InformationsquelleAutor Jason Iwinski
Fragen Sie,
Ja, sollten Sie. Sollten Sie auch aussetzen der Version in einem versteckten input-als sein Geschäft ist, um zu verhindern, gleichzeitige änderungen an derselben Einheit. Die StaleObjectException Hinweise, du hast die Versionierung eingeschaltet ist, und in diesem Fall, das update wird nur funktionieren, wenn die version mit dem Wert (Int32), die Sie senden zurück, der identisch ist mit dem in der Datenbank.
Können Sie sich immer um ihn herum, durch das Neuladen der Person und Zuordnung ist es, sicherzustellen, dass die Version Wert ist wahrscheinlich zu passen, aber das scheint zu untergraben und seinen Zweck.
IMHO, würde ich die Entitäts-ID und Version in einem versteckten Eingang, und beim postback, laden Sie die Entität, und anzeigen der Daten. So, wie Ivan Korytin schlägt vor, Sie nicht zu tragen haben um Eigenschaften, die nicht benötigt werden. Sie können auch mit dem Umstand auf der controller-Ebene und fügen Sie eine Validierung Fehler haben, anstatt NHibernate sagen Sie Ihr Objekt veraltet ist.
Ivan Korytin beschreibt die standard-Verfahren für die Handhabung eine einfache Bearbeitung einer Entität. Das einzige Problem mit seiner Antwort ist, dass es keine Adresse, die Version-Eigenschaft. IMHO sollte die Datenbank nicht versioniert werden, oder die Eigenschaft Version zählen sollte.
Automapper
mit entsprechenden viewmodels Ergebnis in Einheiten Ablösung beim Bearbeiten/aktualisieren? Mit einer anderen 3d-party sowtware macht die Anwendung komplexer. Was ich wissen möchte ist, wie Sie zu machen, Bearbeiten/aktualisieren mitnhibernate
ohne abnehmen Entitäten.Der Prozess, der bewirkt, dass die Loslösung letztlich ist, dass Sie in einer web-Umgebung, keine desktop-Umgebung. Sagen wir, du bist mit ASP.Net MVC, und der Benutzer macht einen Wechsel in ein edit-Formular aus und klickt auf "Absenden". Der binder Modell wird eine Bindung zu einem "Modell" (in diesem Fall Ihre Domäne-Objekt), die einen null-Konstruktor und tun Ihr bestes, um Werte zuzuweisen, die "Modell-Objekt" basierend auf dem, was gepostet wurde, zurück.
Wenn Sie absolut bestehen auf der Suche nach einer Lösung, in der die resultierende Modell-Objekt ist eine voll angeschlossene Einheit, ich bin mir sicher, dass es einen Weg gibt, aber interessant wäre es nur in einem akademischen Sinne. In Bezug auf die Entwicklung von software und Bereitstellung von software effizient und Aufrechterhaltung einer code-Basis, die leicht für andere Entwickler, die kommen später, es ist viel klüger, Folgen Sie den standard-Ansätze. Es gibt keine Notwendigkeit einer 3rd-party-automapper: Sie können die Karte die Eigenschaften manuell, und es ist nichts ungültig zu diesem Ansatz.
InformationsquelleAutor brightgarden
"nicht gespeicherte Wert" fehlt. daher NH denkt, dass Guid.Leer ist eine gültige id
InformationsquelleAutor Firo
Wenn Sie aktualisieren möchten einige Unternehmen Felder, die Sie nicht verwenden müssen, die Sitzung.Update(),
verwenden session.Flush() vor dem schließen der Transaktion.
Sitzung.Update() -> Aktualisieren der persistenten Instanz mit dem Bezeichner, den der transient-Instanz.
InformationsquelleAutor Anton
Wenn Sie von uns keine Antwort aus, die hier geholfen haben, versuchen Sie, was für eine "ID" in Ihrer Organisation senden.
Ich habe das gleiche problem, aber am Ende, sah ich, dass ich das ändern der ID auf einen anderen Wert (in NHibernate die id wird selbst erzeugt, wenn Sie es so eingerichtet!).
Also, bottom line, überprüfen Sie, ob die Struktur der Daten, die Sie senden und die Werte, die entsprechen, was Sie erwarten, um zu senden.
Hoffe mir kann jemand helfen! 🙂
InformationsquelleAutor C3PO
Nachdem alle es hilft, aber ich denke, es ist schrecklich:
Auch wenn ich
HiddenFor
Felder aufEdit
anzeigen fürID
(undVersion
) die ID übergeben wird, ist gewöhnlich einGuid.Empty
die besagt, dassemployee
transient ist.Ich bin wirklich dankbar für Eure Hilfe Jungs!
Fragen
I know what viewmodels are, but quite not understood how does it help with detaching
.Why if I put TextBoxFor(e => e.ID) on Edit view it binds employee like a transient entity without saving the ID value?
Sie können versuchen, halten alle den Inhalt Ihrer Frage in der Frage selbst. Das ist ein Teil der Etikette sich hier um und es ist einfacher für alle zu verstehen, Sie Frage. Wie auch immer, wie sind Sie mit der Erstellung von Kennungen (IDs) ?
InformationsquelleAutor lexeme