Sam*_*Sam 8 .net c# entity-framework
错误消息:附加类型的实体失败,因为同一类型的另一个实体已具有相同的主键值.
问题:如何以类似的方式附加实体,如下面的代码中的AttachActivity方法所示?
我必须假设上面的错误消息的"另一个实体"部分是指存在于内存但超出范围(??)的对象.我注意到这一点,因为我尝试附加的实体类型的DBSet的Local属性返回零.
我有理由相信实体在上下文中不存在,因为我逐步完成代码并在创建时观察上下文.在创建dbcontext之后,实体将立即添加到几行中.
我正在测试这里指定的附加实体:找出实体是否附加到dbContext的最合理方法是什么?
当在visual studio的locals窗口中查看本地时,我看到没有类型为Activity的实体(无论ID),除了我想要附加的实体.
代码按以下顺序执行:Try - > ModifyProject - > AttachActivity
代码在注释行的AttachActivity中失败.
请注意调试注释之间的代码,如果已将任何实体添加到上下文中,则将抛出该代码.
private string AttachActivity(Activity activity)
{
string errorMsg = ValidateActivity(activity); // has no code yet. No. It does not query db.
if(String.IsNullOrEmpty(errorMsg))
{
// debug
var state = db.Entry(activity).State; // Detached
int activityCount = db.Activities.Local.Count;
int projectCount = db.Activities.Local.Count;
if (activityCount > 0 || projectCount > 0)
throw new Exception("objects exist in dbcontext");
// end debug
if (activity.ID == 0)
db.Activities.Add(activity);
else
{
db.Activities.Attach(activity); // throws here
db.Entry(activity).State = System.Data.Entity.EntityState.Modified;
}
}
return errorMsg;
}
public int ModifyProject(Presentation.PresProject presProject, out int id, out string errorMsg)
{
// snip
foreach (PresActivity presActivity in presProject.Activities)
{
Activity a = presActivity.ToActivity(); // returns new Activity object
errorMsg = ValidateActivity(a); // has no code yet. No. It does not query db.
if (String.IsNullOrEmpty(errorMsg))
{
a.Project = project;
project.Activities.Add(a);
AttachActivity(a);
}
else
break;
}
if (string.IsNullOrEmpty(errorMsg))
{
if (project.ID == 0)
db.Projects.Add(project);
else
db.AttachAsModfied(project);
saveCount = db.SaveChanges();
id = project.ID;
}
return saveCount;
}
Run Code Online (Sandbox Code Playgroud)
这是新闻dbContext的类:
public void Try(Action<IServices> work)
{
using(IServices client = GetClient()) // dbContext is newd up here
{
try
{
work(client); // ModifyProject is called here
HangUp(client, false);
}
catch (CommunicationException e)
{
HangUp(client, true);
}
catch (TimeoutException e)
{
HangUp(client, true);
}
catch (Exception e)
{
HangUp(client, true);
throw;
}
}
Run Code Online (Sandbox Code Playgroud)
我不是问:我如何使用AsNoTracking有什么不同.AsNoTracking()会做什么?
Moh*_*our 25
避免接收此错误的一种解决方案是使用Find方法.在附加实体之前,查询DbContext所需的实体,如果实体存在于内存中,则获得本地实体,否则将从数据库中检索实体.
private void AttachActivity(Activity activity)
{
var activityInDb = db.Activities.Find(activity.Id);
// Activity does not exist in database and it's new one
if(activityInDb == null)
{
db.Activities.Add(activity);
return;
}
// Activity already exist in database and modify it
db.Entry(activityInDb).CurrentValues.SetValues(activity);
db.Entry(activityInDb ).State = EntityState.Modified;
}
Run Code Online (Sandbox Code Playgroud)
小智 6
附加类型的实体失败,因为相同类型的另一个实体已具有相同的主键值.当使用该Attach方法或将实体的状态设置为Unchanged或者Modified图中的任何实体具有冲突的键值时,可能会发生这种情况.这可能是因为某些实体是新的并且尚未收到数据库生成的键值.在这种情况下使用Add.
解决方案就是这样
如果你不得不使用GetAll()
public virtual IEnumerable<T> GetAll()
{
return dbSet.ToList();
}
Run Code Online (Sandbox Code Playgroud)
改成
public virtual IEnumerable<T> GetAll()
{
return dbSet.AsNoTracking().ToList();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
19276 次 |
| 最近记录: |