以常见的权限关系来说,User\Role 2个实体是多对多关系,其POCO类似:
[DataContract]
public class User
{
public User()
{
this.Id = Guid.NewGuid();
this.Roles = new List<Role>();
}
[Key]
[DataMember]
public Guid Id
{
get;
private set;
}
[DataMember]
public string UserName{get;set;}
[DataMember]
public string PassWord{get;set;}
[DataMember]
public virtual List<Role> Roles{get;set;}
}
创建服务类似:
ServiceResult UpdateUser(User user);
这时候,我们知道,如果WCF与EF结合使用,有一些注意点:一,WCF传递的需要是POCO类,且不能循环引用(这一点通过在实体类添加[DataContract(IsReference=true)]即可),
二一个问题是EF的延迟加载和代理实例机制,导致EF查询结果并非POCO类,而是代理类,所以需要关系EF代理实例模式:Configuration.ProxyCreationEnabled = false;
现在问题来啦,如何实现UpdateUser方法呢,一般我们会用IDbSet.Attach()方法来更新,代码如:
m_DbSet.Attach(entity);
this.DbContext.Entry<T>(entity).State = EntityState.Modified;
this.DbContext.SaveChanges();
但是这时候你就会发现,由于EF为了支持WCF服务已经关闭了ProxyCreationEnabled ,所以无论如何,这里的Attach方法是不能执行成功的,
那这时候你会想,那我不采用Attach方法,先Delete实体,再重新添加行不行呢,
NO no no ,由于EF在SaveChanges的时候会根据实体关系,自动修改数据表,所以当你删除User时候的时候会删除User表以及User_Role表中的记录,此时再添加User实体的话,会向User表添加User,User_Role表添加关系,Role表添加Role(因为User.Roles的存在),
这时候你会发现Role表添加Role就不行了,因为记录已经存在了;所以这种方式也不能很好的解决问题!!
怎么办呢,我暂时也不知道怎么办,所以来此求助各位大牛~~看看有什么经验,好的处理方法!
ps:Data Services、Ria services暂时不考虑,因为我的应用需要对具体的操作进行授权!非Web系统!
这个弄的太复杂了吧,你如果用wcf那么调用wcf后就与调用方没什么关系了,数据库操作就在写在WCF服务端啊
呵呵。,主要是为了方便, 不想一个实体也N个对应修改属性的服务!
直接通过修改实体,提交更新,是最好最直接的办法, 这其中关键就是要控制好服务端与客户端 的实体状态一致性,和POCO完整性;这可能也是后来Data Services 和 Ria Services 推出的原因之一吧!
问题已经得到解决了,稍后我会写详细的设计方式到博客;
现在简单说下 关于更新这一问题的解决方式:
Model First方式请参照:
Code-First方式需要如下操作:
public virtual void Update(T entity)
{
T current = this.Where(m => m.Id.Equals(entity.Id))
.SingleOrDefault();
if (current != null)
{
var context = ((IObjectContextAdapter)DbContext).ObjectContext;
ObjectStateEntry objectStateEntry;
if (context.ObjectStateManager.TryGetObjectStateEntry(current, out objectStateEntry))
{
objectStateEntry.ApplyCurrentValues(entity);
objectStateEntry.SetModified();
this.Commit();
}
}
}
注意,在Code First这种方式中,如果实体包含外键关系,可能无关更新关系属性, 所以要求增加相应的服务用于操作外键关系属性, 具体原因稍后我在分析下!
T current = this.Where(m => m.Id.Equals(entity.Id))
.SingleOrDefault();
请问this指的是什么? 这条语句好像检索不出T current啊?
用EmitMapper怎么样?
public virtual void Update(TEntity entityToUpdate)
{
var entry = context.Entry(entityToUpdate);
if (entry.State == EntityState.Detached)
{
var entityOrigin = GetByID(entityToUpdate.ID);
EmitMapper.ObjectMapperManager
.DefaultInstance.GetMapper<TEntity, TEntity>()
.Map(entityToUpdate, entityOrigin);
}
}