这就是我们如何在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;
}
答案 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
块 - 虽然可能是不必要的 - 可以很容易地被放入一个简单的实用方法中,以便更加干燥。