转自
使用ADO实体框架(EF)对建立了关系的表新增记录时出现“一个实体对象不能由多个 IEntityChangeTracker 实例引用”错误,网上反复搜索后,没有找到解决办法,微软的文档也说的含糊不清,实际上,“IEntityChangeTracker ”到底是什么,我到现在也还是模模糊糊的。
问题现象:
一个角色表,一个用户表,用户表中的RoleId引用角色表中的RoleId。对用户表添加记录时,出现上述问题。
为了便于以后的维护和升级,我仍然对项目进行了分层,有了实体框架,数据访问层和实体模型层自然可以用实体框架模型取代。业务层则仍按照传统方式对每一个表都创建了相应的类。这里我就创建了分别处理角色和用户的业务层:RoleManager和UserManager。
(题外话:MVC比传统的三层结构更好用,不过这个项目比较紧,MVC我还没有完全搞清楚,有些关键问题解决不了,所以这个项目还是决定用三层结构)
添加用户数据的代码如下:
表示层:
dmUser user=new User{UserId="test",UserName="test"}; //dmUser是表dmUser在实体模型中的映射
user.dmRoleReference.Value=RoleManager.GetRoleById(roleId); //添加User表的关联对象
UserManager.Add(user); //调用UserManager中的Add方法向数据库添加记录
UserManager.Add方法中的主要代码:
using(Entities db=new Entitles) //Entities,数据库的实体模型
{
db.AddToUser(user); //这里出现本文所说的错误
db.SaveChanges();
}
百思不得其解,反复上网搜索,没有找到答案,虽然找到一篇博文说解决了这个问题,但其所用的方法实在不敢恭维,应该会对程序造成很大的负面影响,而且他那个方法也不能适用到我的代码中。
“对象服务使用 的实例来跟踪对附加到 ObjectContext 的对象的更改。对于每个被跟踪对象,都有一个 IEntityChangeTracker 实例。”微软的某一篇文档中有这样一句话,给了我一点提示。
经过多次编写代码验证,终于明白,使用EF更新数据时,如果要更新的对象有相关的对象(换句话说,就是要更新的表有主外键关系),这些对象必须来自同一个IEntityChangeTracker 。
而我的问题就出在user.dmRoleReference.Value=RoleManager.GetRoleById(roleId); 这里,在RoleManager.GetRoleById(roleId)方法中的实体对象和UserManager.Add方法中使用的实体对象不是同一个对象,也就产生了不同的IEntityChangeTracker 实例,因此出现本文所说的错误。
对UserManager.Add方法做如下修改即可
using(Entities db=new Entitles) //Entities,数据库的实体模型
{
user.dmRoleReference.Value=db.dmRole.First(r=>r.RoleId==roleId);
db.AddToUser(user);
db.SaveChanges();
}
虽然这样一来,roleId需要做为参数从表示层传递到Add方法中,但总比某位台湾同行说处理这种问题用SQL语句要好吧(在google搜索时找这位同行的博客,他也遇到这个问题,他的解决方法就是直接使用SQL语句……),EF还是很强大滴,能省很多事……