1

这就是我们在 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;
}
4

2 回答 2

6

你为什么要对自我跟踪实体这样做?这有什么问题:

[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;
}
于 2011-06-24T08:03:03.627 回答
2

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

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

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

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

于 2011-06-23T23:34:04.513 回答