EF4 / WCF SaveChanges()最佳实践

时间:2011-06-23 23:07:32

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

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

2 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:2)

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

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

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

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