为什么实体框架在应该更新的时候却插入了?

发布于 2024-11-10 11:04:39 字数 2551 浏览 2 评论 0 原文

我使用以下 RIA 服务调用来注册并返回 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;
}

正如您所看到的,它调用一个返回项目 ID 的存储过程。它使用此 ID 查找 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();
}

它绝对没有任何作用。它没有保存该项目。

I use the following RIA Services call to register and return a Project entity.

// 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;
}

As you can see, it calls a stored procedure that returns a project ID. It uses this ID to look up the Project entity itself and return it. When the Project entity is returned to the client it is detached. I attach it to the DomainContext and modify it.

// 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";
} 

At this point it has an entity state of Modified. When I submit changes it gives me an exception regarding a UNIQUE KEY violation as if it is trying to insert it rather than update it.

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

I'm using the same DomainContext instance for all operations. Why should this not work?
What's going wrong? This is rather frustrating.

Edits:

I tried this (as suggested by Jeff):

[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();
}

It did absolutely nothing. It didn't save the project.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

用心笑 2024-11-17 11:04:39

如果在服务器端添加一个 SaveProject 方法并将对象发送回服务器进行保存,会发生什么情况?

我没有使用 RIA 服务完成 EF,但我总是将对象发送回服务器进行保存。我假设 SubmitChanges 调用您正在为您正确连接所有内容,以便将其发送回服务器,但也许它做错了什么,手动处理它可以修复它。

What happens if you add a SaveProject method on the server side and send the object back to the server for saving?

I've not done EF with RIA Services, but I've always sent my objects back to the server for saving. I'm assuming that SubmitChanges call you are making wires up everything properly for you for sending it back to the server, but perhaps it is doing something wrong and handling it manually will fix it.

紫瑟鸿黎 2024-11-17 11:04:39

我目前没有源代码,但我看到它建议您为 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;
            }

        }

I dont have the source at the moment but I have seen it recommended that you use a new context for each operation in Silverlight. I ran into a similar problem today and it was because I was using a Service level context that was remembering previous values that I didnt want, I changed to creating a new context for each service call and the behavior became what I expected.

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;
            }

        }
李白 2024-11-17 11:04:39

至于不能使用单例全局 DomainContext 的概念,这实际上是有争议的。在我的项目中,我使用单例 DomainContext 没有任何问题。在其他项目中,我们为应用程序中的不同模块创建了一个新的 DomainContext,其中实体被重用。肯定有优点和缺点。看:
处理 DomainContext 的策略(外部博客)

As for the notion that one can't use a singleton global DomainContext, this is actually debatable. In my project I use a singleton DomainContext with no issues. In other projects, we have created a new DomainContext for different modules in the app where the entities are reused. There are definitely pros and cons. See:
Strategies for Handling Your DomainContext (external blog)

一紙繁鸢 2024-11-17 11:04:39

问题似乎在于,当您将项目附加到 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
    } 
});

It seems that the problem is that when you attach your project to the DomainContext it checks the _context.Projects entityset and isn't finding an entity with that primary key, and then assumes that the newly attached entity doesn't exist serverside yet and that submitting changes should insert it. A possible workaround might be to explicitly load the newly created Project into the DomainContext. It would ensure that it sets the correct state on the entity--that is, that the project already exists on the server and that that it's an update instance, rather than an insert instance.

So maybe something like:

//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
    } 
});
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文