Zunächst möchte ich sagen, dass ich die zugehörigen Beiträge (insbesondere EF 4.1 SaveChanges not updating navigation or reference properties, Entity Framework Code First - Why can't I update complex properties this way? und Entity Framework 4.1 RC (Code First) - Entity not updating over association) gelesen habe.Eigenschaft nicht nach SaveChanges (EF-Datenbank zuerst) aktualisiert
Allerdings konnte ich mein Problem nicht lösen. Ich bin ziemlich neu im Entity Framework, also denke ich, dass ich diese Post-Antworten falsch verstanden habe. Jedenfalls wäre ich wirklich dankbar, dass mir jemand helfen konnte zu verstehen, weil ich ziemlich feststecke.
Ich habe zwei Tabellen:
Person
Item
mit einem Nullable-PersonId
und einType
Ein Element kann einen Eigentümer haben, oder nicht. Folglich hat Person
eine Items
Eigenschaft, die ein IEnumerable von Item
ist.
Eine Person kann eine nur Item
nach Typ haben. Wenn die Person sich ändern will, kann er seine aktuelle Element von einem anderen des gleichen Typs in seine Einzelteile ersetzen:
public class MyService
{
private PersonRepo personRepo = new PersonRepo();
private ItemRepo itemRepo = new ItemRepo();
public void SwitchItems(Person person, Guid newItemId)
{
using (var uof = new UnitOfWork())
{
// Get the entities
Item newItem = itemRepo.Get(newItemId);
Item oldItem = person.Items.SingleOrDefault(i => i.Type == newItem.Type)
// Update the values
newItem.PersonId = person.Id;
oldItem.PersonId = null;
// Add or update entities
itemRepo.AddOrUpdate(oldItem);
itemRepo.AddOrUpdate(newItem);
personRepo.AddOrUpdate(person);
uof.Commit(); // only does a SaveChanges()
}
}
}
Hier ist die Repositorys Struktur und die AddOrUpdate
Methode:
public class PersonRepo : RepositoryBase<Person>
{
...
}
public class RepositoryBase<TObject> where TObject : class, IEntity
{
protected MyEntities entities
{
get { return UnitOfWork.Current.Context; }
}
public virtual void AddOrUpdate(TObject entity)
{
if (entity != null)
{
var entry = entities.Entry<IEntity>(entity);
if (Exists(entity.Id))
{
if (entry.State == EntityState.Detached)
{
var set = entities.Set<TObject>();
var currentEntry = set.Find(entity.Id);
if (currentEntry != null)
{
var attachedEntry = entities.Entry(currentEntry);
attachedEntry.CurrentValues.SetValues(entity);
}
else
{
set.Attach(entity);
entry.State = EntityState.Modified;
}
}
else
entry.State = EntityState.Modified;
}
else
{
entry.State = EntityState.Added;
}
}
}
}
Diese funktioniert sehr gut und die alten und neuen Artikel 'PersonId
Eigenschaften werden korrekt in der Datenbank aktualisiert. Wenn ich jedoch person.Items
nach dem SaveChanges()
überprüfe, erscheint das alte Element immer noch anstelle des neuen und ich brauche es, um die Steuerwerte der Seite zu aktualisieren.
Obwohl ich die Beiträge mit dem gleichen Problem gelesen habe, konnte ich es nicht lösen ... Ich versuchte viele Dinge, vor allem Aufruf entities.Entry(person).Collection(p => p.Items).Load()
, aber bekam jedes Mal eine Ausnahme, die ich versuchte.
Wenn jemand eine Idee hat, fühlen Sie sich bitte frei, ich kann etwas mehr Code bei Bedarf hinzufügen.
Vielen Dank!
EDIT: UnitOfWork
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Data.Entity.Infrastructure;
using System.Data.Objects;
public class UnitOfWork : IDisposable
{
private const string _httpContextKey = "_unitOfWork";
private MyEntities _dbContext;
public static UnitOfWork Current
{
get { return (UnitOfWork)HttpContext.Current.Items[_httpContextKey]; }
}
public UnitOfWork()
{
HttpContext.Current.Items[_httpContextKey] = this;
}
public MyEntities Context
{
get
{
if (_dbContext == null)
_dbContext = new MyEntities();
return _dbContext;
}
}
public void Commit()
{
_dbContext.SaveChanges();
}
public void Dispose()
{
if (_dbContext != null)
_dbContext.Dispose();
}
}
Zwei Lösungen, die
Lösung 1 (Nachladen aus dem Kontext nach Savechanges) arbeitete
public partial class MyPage
{
private MyService service;
private Person person;
protected void Page_Load(object sender, EventArgs e)
{
service = new MyService();
person = service.GetCurrentPerson(Request.QueryString["id"]);
...
}
protected void SelectNewItem(object sender, EventArgs e)
{
Guid itemId = Guid.Parse(((Button)sender).Attributes["id"]);
service.SelectNewItem(person, itemId);
UpdatePage();
}
private void UpdatePage()
{
if (person != null)
person = service.GetCurrentPerson(Request.QueryString["id"]);
// Update controls values using person's properties here
}
}
public class MyService
{
private PersonRepo personRepo = new PersonRepo();
private ItemRepo itemRepo = new ItemRepo();
public void SwitchItems(Person person, Guid newItemId)
{
using (var uof = new UnitOfWork())
{
// Get the entities
Item newItem = itemRepo.Get(newItemId);
Item oldItem = person.Items.SingleOrDefault(i => i.Type == newItem.Type)
// Update the values
newItem.PersonId = person.Id;
oldItem.PersonId = null;
// Add or update entities
itemRepo.AddOrUpdate(oldItem);
itemRepo.AddOrUpdate(newItem);
personRepo.AddOrUpdate(person);
uof.Commit(); // only does a SaveChanges()
}
}
}
Lösung 2 (Update-Datenbank und Eigentum)
public partial class MyPage
{
private MyService service;
private Person person;
protected void Page_Load(object sender, EventArgs e)
{
service = new MyService();
person = service.GetCurrentPerson(Request.QueryString["id"]);
...
}
protected void SelectNewItem(object sender, EventArgs e)
{
Guid itemId = Guid.Parse(((Button)sender).Attributes["id"]);
service.SelectNewItem(person, itemId);
UpdatePage();
}
private void UpdatePage()
{
// Update controls values using person's properties here
}
}
public class MyService
{
private PersonRepo personRepo = new PersonRepo();
private ItemRepo itemRepo = new ItemRepo();
public void SwitchItems(Person person, Guid newItemId)
{
using (var uof = new UnitOfWork())
{
// Get the entities
Item newItem = itemRepo.Get(newItemId);
Item oldItem = person.Items.SingleOrDefault(i => i.Type == newItem.Type)
// Update the values
newItem.PersonId = person.Id;
oldItem.PersonId = null;
person.Items.Remove(oldItem);
person.Items.Add(newItem);
// Add or update entities
itemRepo.AddOrUpdate(oldItem);
itemRepo.AddOrUpdate(newItem);
personRepo.AddOrUpdate(person);
uof.Commit(); // only does a SaveChanges()
}
}
}
Ich bin nicht sicher, dass auf einer Entität den Fremdschlüssel zu ändern EF löst es zu platzieren in der richtigen Sammlung. Was passiert, wenn Sie einen neuen Kontext hochfahren und von der Datenbank neu laden? – user2697817
Vielen Dank für Ihre Antwort. Ja, wenn ich es von der Datenbank neu lade funktioniert es (es funktioniert übrigens auch nach dem folgenden Page_Load). Wenn ich 'Item currentItem = entities.Items.SingleOrDefault (i => i.PersonId == Person.Id && i.TypeId == newItem.TypeId);' direkt nach SaveChanges überprüfe, ist 'currentItem' vollkommen in Ordnung. Aber ich würde wirklich brauchen, dass die Eigenschaft up-to-date ist, um die Seitensteuerungen zu aktualisieren. Zurzeit muss ich die Seite aktualisieren (gehe zu Page_Load und lade die aktuelle Person neu), um zu sehen, dass sich das Element geändert hat. –
@jlvaquero: Natürlich habe ich meinen ersten Post mit dem UnitOfWork-Code bearbeitet :) –