问题描述
|
这就是我们在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;
}
解决方法
您为什么要使用自我跟踪实体?这有什么问题:
[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服务中公开其Entity Framework对象。通常将实体框架视为数据访问层,而WCF更像是前端层,因此将它们放在不同的层上。
WCF方法中使用了数据传输对象(DTO)。通常,这是一个POCO,它没有任何状态跟踪。然后将DTO手动或通过诸如AutoMapper的框架映射到实体。
通常,客户应该知道它们是“添加”还是“更新”对象,而我个人更希望它们是服务接口上的两个独立操作。另外,我绝对会要求他们使用单独的方法删除对象。但是,如果您绝对需要通用的“保存”,则应该基于主键值的存在(或不存在)来判断给出的对象是否为“新”。 。
许多代码可以放入通用实用程序中。例如,假设您的T4模板在实体的键值上产生属性,则可以自动确定键值是否存在并相应地执行插入/更新。同样,您正在使用的“ 2”块(虽然可能不是必需的)可以轻松地放入简单的实用程序方法中,使其更加干燥。