【问题标题】:EF4/WCF SaveChanges() Best PracticeEF4/WCF SaveChanges() 最佳实践
【发布时间】:2011-06-23 23:07:32
【问题描述】:

这就是我们在 WCF 中为 EF 实体实现通用 Save() 服务的方式。 TT 为我们完成工作。即使我们对此没有任何问题,但我不想假设这是最好的方法(即使它可能是)。你们看起来非常聪明和乐于助人,所以我想我会提出这个问题:

有没有更好的办法?

[OperationContract]
public User SaveUser(User entity)
{
    bool _IsDeleted = false;
    using (DatabaseEntities _Context = new DatabaseEntities())
    {
        switch (entity.ChangeTracker.State)
        {
            case ObjectState.Deleted:
                //delete
                _IsDeleted = true;
                _Context.Users.Attach(entity);
                _Context.DeleteObject(entity);
                break;
            default:
                //everything else
                _Context.Users.ApplyChanges(entity);
                break;
        }
        // now, to the database
        try
        {
            // try to save changes, which may cause a conflict.
            _Context.SaveChanges(System.Data.Objects.SaveOptions.None);
        }
        catch (System.Data.OptimisticConcurrencyException)
        {
            // resolve the concurrency conflict by refreshing 
            _Context.Refresh(System.Data.Objects.RefreshMode.ClientWins, entity);
            // Save changes.
            _Context.SaveChanges();
        }
    }
    // return
    if (_IsDeleted)
        return null;
    entity.AcceptChanges();
    return entity;
}

【问题讨论】:

  • 也许最佳 做法是不要编写会导致OptimisticConcurrencyExceptions 的代码?是什么导致它们发生?我以前从未见过。
  • @StriplingWarrior 有一个很好的观点。你真的有没有从你的代码中发现抛出这个异常?
  • 仅在调试情况下。没错。
  • @JerryNixon-MSFT 不错的方法,您如何知道 EF 实体是否已被修改?因为 POCO 实体类没有任何属性来设置它,还是我错了?感谢分享。
  • @VAAA 可追踪实体有办法。是的。

标签: wcf entity-framework self-tracking-entities savechanges


【解决方案1】:

您为什么要对自我跟踪实体进行此操作?这有什么问题:

[OperationContract]
public User SaveUser(User entity)
{
    bool isDeleted = false;
    using (DatabaseEntities context = new DatabaseEntities())
    {
        isDeleted = entity.ChangeTracker.State == ObjectState.Deleted;
        context.Users.ApplyChanges(entity); // It deletes entities marked for deletion as well

        try
        {
            // no need to postpone accepting changes, they will not be accepted if exception happens
            context.SaveChanges(); 
        }
        catch (System.Data.OptimisticConcurrencyException)
        {
            context.Refresh(System.Data.Objects.RefreshMode.ClientWins, entity);
            context.SaveChanges();
        }
    }

    return isDeleted ? null : entity;
}

【讨论】:

  • 嗨,你怎么知道实体状态是否被删除?你如何在客户端上跟踪它。因为我假设您将实体从 WCF 发送到客户端,但实体没有任何属性来设置状态不是吗?非常感谢
【解决方案2】:

如果我没记错的话,人们通常不会在 WCF 服务中直接公开他们的实体框架对象。实体框架通常被认为是一个数据访问层,而 WCF 更像是一个前端层,因此它们被放在不同的层上。

在 WCF 方法中使用了数据传输对象 (DTO)。这通常是一个 POCO,它没有任何状态跟踪。然后通过手动或 AutoMapper 等框架将 DTO 映射到实体。

通常客户应该知道他们是在“添加”还是“更新”一个对象,我个人更希望这些是服务接口上的两个独立操作。另外,我肯定会要求他们使用单独的方法来删除对象。但是,如果您绝对需要一个通用的“保存”,您应该能够根据主键值的存在(或不存在)来判断您获得的对象是否是“新的”。

很多代码都可以放入通用实用程序中。例如,假设您的 T4 模板在实体的键值上生成属性,您可以自动确定键值是否存在并相应地执行插入/更新。此外,您正在使用的 try SaveChanges catch retry 块 - 虽然可能不必要 - 可以很容易地放入一个简单的实用程序方法中以更加干燥。

【讨论】:

  • 我们不会按照您描述的方式进行操作,而且效果非常好。跨层共享程序集中的自我跟踪实体是无缝的。
  • @JerryNixon:所以你直接发送你的WCF客户端实体,客户端修改实体并将它们发送回服务?这很酷,它可以如此无缝地工作。感谢分享。
  • 是的!不仅如此,我还完全忠实于实体,因为它们是外部的,而不是客户端的代理。 AKA 他们可以有方法!
  • @StriplingWarrior 我有这种方法,WCF 向客户端发送一个 POCO 类(实际上是一个 EF 实体)。此 POCO 没有任何状态跟踪等。保存时如何知道实体是否在 WCF 服务中被删除或更改?有什么样品可以看吗?感谢分享。+
  • @VAAA:我对你的问题有点困惑。大概如果您使用的是没有状态跟踪的 POCO,您不会通过调用 .Delete() 来删除它,对吧?因此,删除它应该是在 WCF 服务上调用 Delete 方法并将对象(或其 ID)作为参数传递给该方法的问题。因为它不是跟踪状态,所以您也无法知道对象是否已“更改”——您只能将其与数据存储中的内容进行比较,看看是否不同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-23
  • 1970-01-01
  • 1970-01-01
  • 2011-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多