Как мне отредактировать объект, используя подход Entity Framework Code First? - PullRequest
1 голос
/ 10 января 2011

Я уже несколько дней рвал на себе волосы, и, прежде чем полностью облысеть, пришло время спросить всех, кто умнее меня, как это сделать.

Я использую Entity Framework 4 с кодомПервые CTP 5 и MVC 3.

Сообщение об исключении прямо сейчас: «Объект с тем же ключом уже существует в ObjectStateManager. ObjectStateManager не может отслеживать несколько объектов с одним и тем же ключом.»

Сначала вот контроллер, которому отправляется форма редактирования:

public ActionResult Save(ClientEntity postedClient)
    {
        try
        {
            if (ModelState.IsValid)
            {
                Base.clientInterface.Save(postedClient);
                return RedirectToAction("Index");
            }
        }
        catch (Exception)
        {

            throw;
        }

        SetupManageData(null, postedClient);
        return View("Manage");

    }

Метод Save в клиентском интерфейсе таков:

public void Save(ClientEntity theClient)
    {
        SetContext();


        if (theClient.clientId == 0)
            this.pContext.Clients.Add(theClient);
        else
        {
            ClientEntity existingClient = GetSingle(theClient.clientId); // Get the existing entity from the data store.

            // PseudoCode: Merge existingClient and theClient - Can this be done without using ObjectStateManager?               
            // PseudoCode: Attach merged entity to context so that SaveChanges will update it in the database - is this correct?
        }

        this.pContext.SaveChanges();

    }

    private void SetContext()
    {
        if (this.pContext == null)
            this.pContext = new PersistanceContext();           
    }

Контекст сопротивления - это DBContext, который выглядит следующим образом:

public class PersistanceContext : DbContext
{
    public DbSet<ClientEntity> Clients { get; set; }
}

Ответы [ 2 ]

0 голосов
/ 16 января 2011

Каков стиль жизни clientInterface?это одноэлементный файл или что-то, что поддерживает его в нескольких запросах?

Я предполагаю, что он содержит живой экземпляр контекста базы данных, который использовался для выборки объекта в запросе GET, и когда POST пытается(повторно) добавьте клиентскую сущность в контекст, где старая все еще существует, и они конфликтуют.

Попробуйте уничтожать объект, который находится за clientInterface, при каждом запросе.Возможно, используйте DI-контейнер, который поддерживает образ жизни для каждого веб-запроса, поэтому вам не нужно об этом беспокоиться.

Надеюсь, мое предположение было верным, и это поможет.

0 голосов
/ 11 января 2011

Это должно работать.

    if (theClient.clientId == 0)
    {
        this.pContext.Clients.Add(theClient);
    }
    else
    {
        ClientEntity existingClient = this.pContext.Clients.Single(o => o.ClientId == theClient.ClientId);

        // map properties
        existingClient.Name = theClient.name;
        // ....

    }

    this.pContext.SaveChanges();

[Изменить]

Проще (ИМХО) разделить создание и редактирование объектов на 2 отдельных представления и избежать сопоставления свойств, которые я использую TryUpdateModel.

[HttpPost]
public ViewResult Edit(int clientID, FormCollection collection) 
{
    var client = pContext.Clients.SingleOrDefault(o => o.ID == clientID);

    if(!TryUpdateModel(client, collection)) 
    {
        ViewBag.UpdateError = "Update Failure";
    }
    else
    {
        db.SubmitChanges();
    }

    return View("Details", client); 
}

[HttpPost]
public ViewResult Create(FormCollection collection) 
{
    var client = new Client();

    if(!TryUpdateModel(client, collection)) 
    {
        ViewBag.UpdateError = "Create Failure";
    }
    else
    {
        db.Clients.Add(client);
        db.SubmitChanges();
    }

    return View("Details", client); 
}
...