Почему Entity Framework вставляет, когда он должен обновить? - PullRequest
2 голосов
/ 28 мая 2011

Я использую следующий вызов RIA Services для регистрации и возврата объекта Project.

// On Server; inside RIA Domain Service
[Invoke]
public Project CreateNewProject(String a_strKioskNumber)
{
  Decimal dProjectID = ObjectContext.RegisterProjectNumber(a_strKioskNumber)
                       .FirstOrDefault() ?? -1m;

  // Tried this but it returned zero (0)
  //int nChanged = ObjectContext.SaveChanges();

  var project = (from qProject in ObjectContext.Projects.Include("ProjectItems")
                 where qProject.ID == dProjectID
                 select qProject)
                 .FirstOrDefault();

  if (project == null)
    return null;

  return project;
}

Как видите, он вызывает хранимую процедуру, которая возвращает идентификатор проекта. Этот идентификатор используется для поиска самой сущности Project и ее возврата. Когда объект Project возвращается клиенту, он отсоединяется. Я прикрепляю его к DomainContext и модифицирую.

// At Client
_activeProject = a_invokeOperation.Value; // <-- Detached
_context.Projects.Attach(_activeProject); // <-- Unmodified

if (_activeProject != null)
{
  _activeProject.AuthenticationType = "strong"; // <-- Modified
  _activeProject.OwnerID = customer.ID;
  _projectItems.Do(pi => _activeProject.ProjectItems.Add(pi));
  _activeProject.Status = "calculationrequired";
} 

На данный момент он имеет состояние сущности Modified. Когда я отправляю изменения, это дает мне исключение в отношении нарушения UNIQUE KEY, как будто оно пытается вставить его, а не обновить.

// At Client
_context.SubmitChanges(OnProjectSaved, a_callback);

Я использую один и тот же экземпляр DomainContext для всех операций. Почему это не должно работать?
Что не так? Это довольно сложно.

редактирует:

Я попробовал это (как предложено Джеффом):

[Invoke]
public void SaveProject(Project a_project)
{
  var project = (from qProject in ObjectContext.Projects
                 where qProject.ID == a_project.ID
                 select qProject)
                 .FirstOrDefault();

  project.SubmitDate = a_project.SubmitDate;
  project.PurchaseDate = a_project.PurchaseDate;
  project.MachineDate = a_project.MachineDate;
  project.Status = a_project.Status;
  project.AuthenticationType = a_project.AuthenticationType;
  project.OwnerID = a_project.OwnerID;
  project.ProjectName = a_project.ProjectName;
  project.OwnerEmail = a_project.OwnerEmail;
  project.PricePerPart = a_project.PricePerPart;
  project.SheetQuantity = a_project.SheetQuantity;
  project.EdgeLength = a_project.EdgeLength;
  project.Price = a_project.Price;
  project.ShipToStoreID = a_project.ShipToStoreID;
  project.MachiningTime = a_project.MachiningTime;

  int nChangedItems = ObjectContext.SaveChanges();
}

Это абсолютно ничего не сделало. Это не спасло проект.

Ответы [ 4 ]

2 голосов
/ 31 мая 2011

Что произойдет, если вы добавите метод SaveProject на стороне сервера и отправите объект обратно на сервер для сохранения?

Я не выполнял EF со службами RIA, но я всегда отправлял свои объекты обратно на сервер для сохранения. Я предполагаю, что SubmitChanges вызывает, что вы все правильно соединяете и отправляете обратно на сервер, но, возможно, он делает что-то не так, и обработка вручную исправит это.

1 голос
/ 02 июня 2011

Что касается понятия, что один не может использовать одноплодный глобальный DomainContext, это на самом деле спорное.В моем проекте я использую одноэлементный DomainContext без проблем.В других проектах мы создали новый DomainContext для различных модулей в приложении, где объекты используются повторно.Есть определенно плюсы и минусы.См .: Стратегии обработки вашего DomainContext (внешний блог)

1 голос
/ 28 мая 2011

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

public void SaveResponses(ICollection<Responses> items, Action<SubmitOperation> callback)
        {
            try
            {
                SurveysDomainContext _context = new SurveysDomainContext();
                foreach (Responses item in items)
                {
                    _context.Responses.Add(item);
                }

                _context.SubmitChanges(callback, null);
            }
            catch (Exception)
            {

                throw;
            }

        }
0 голосов
/ 02 июня 2011

Кажется, что проблема в том, что когда вы присоединяете ваш проект к DomainContext, он проверяет набор сущностей _context.Projects и не находит сущность с этим первичным ключом, а затем предполагает, что вновь присоединенная сущность не существует на стороне сервера.еще и то, что подающие изменения должны вставить его.Возможным обходным путем может быть явная загрузка вновь созданного проекта в DomainContext.Это гарантировало бы, что оно устанавливает правильное состояние для сущности, то есть, что проект уже существует на сервере и что это экземпляр обновления, а не экземпляр вставки.

Так что может быть что-то вроде:

//after your Project has already been created serverside with the invoke
_context.Load(_context.SomeQueryThatLoadsYourNewlyCreatedProject(), LoadBehavior.RefreshCurrent, (LoadOperation lo) => {
    Project project = lo.Entities.FirstOrDefault(); //is attached and has correct state
    if (project != null)
    {
        project.AuthenticationType = "strong";
        project.OwnerID = customer.ID;
        project.Do(pi => _activeProject.ProjectItems.Add(pi));
        project.Status = "calculationrequired";
        _context.SubmitChanges(); //hopefully will trigger an update, rather than an insert
    } 
});
...