优府网首页
设为首页
点击进入优府网RSS订阅中心
当前位置:首页 >科技 > 科学 > 正文

EF Attach时已存在的处理方式

发布者:陈重       分享 评论 投稿
如果我们在先前的步骤中读取过数据,如varlist=db.Model.ToList();之后再,附加varo=newModel{Id=1};db.Model.Attach(o);就会报,类似这样的错误AttachinganentityoftypeefAutoDetach.Modelfailedbecauseanotherentityofthesametypealreadyhasthesameprimarykeyvalue.ThiscanhappenwhenusingtheAttac…

如果我们在先前的步骤中读取过数据,如

var list = db.Model.ToList();
之后再,附加
var o = new Model { Id = 1 };
db.Model.Attach(o);

就会报,类似这样的错误

Attaching an entity of type 'efAutoDetach.Model' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.

意思是说,在上下文中,已经有一个同样主键的东西了。

这样的错误通常在直接更新时遇到,不是先查出来再更新,而是直接new一个出来,附加上去更新

第一次查询后,本地的local中就已经有相应的实体了。如果我们把local中的实体detach了,那我们新new的对象就可以attch上去了。

Detach的扩展方法

public static void Detach<T>(this DbContext db, T obj) where T : class
{
    ObjectContext oc = ((IObjectContextAdapter)db).ObjectContext;
    oc.Detach(obj);
}

获取主键信息的扩展方法

public static IEnumerable<string> GetEntityKeys<T>(this DbContext db) where T : class
{
    ObjectContext oc = ((IObjectContextAdapter)db).ObjectContext;
    var keys = oc.CreateObjectSet<T>().EntitySet.ElementType.KeyProperties.Select(x => x.Name);
    return keys;
}

我们需要通过主键信息构建一个表达式树,用于从local中获取实体

private static Expression<Func<T, bool>> GetFindExp<T>(T obj, IEnumerable<string> keys) where T : class
{
    var p = Expression.Parameter(typeof(T), "x");

    var keyexps = keys.Select(x =>
    {
        var member = Expression.PropertyOrField(p, x);
        var objV = typeof(T).GetProperty(x).GetValue(obj);
        var eq = Expression.Equal(member, Expression.Constant(objV));
        return eq;
    }).ToList();

    if (keys.Count() == 1)
    {
        return Expression.Lambda<Func<T, bool>>(keyexps[0], new[] { p });
    }

    var and = Expression.AndAlso(keyexps[0], keyexps[1]);
    for (var i = 2; i < keyexps.Count; i++)
    {
        and = Expression.AndAlso(and, keyexps[i]);
    }
    return Expression.Lambda<Func<T, bool>>(and, new[] { p });
}
于是可以找到local中的
public static T FindLocal<T>(this DbContext db, T obj) where T : class
{
    var keys = db.GetEntityKeys<T>();
    var func = GetFindExp<T>(obj, keys).Compile();
    return db.Set<T>().Local.FirstOrDefault(func);
}

最后综合使用上面的几个方法

public static void DetachOther<T>(this DbContext db, T obj) where T : class
{
    var local = db.FindLocal(obj);
    if (local != null)
    {
        db.Detach(local);
    }
}

使用

var o = new Model { Id = 1 };
db.DetachOther(o);
db.Model.Attach(o);
在attach之前,先detachother
以上。

(科技责编:李霞飞 )
2015年05月08日 11:13   [查看原文]  
相关阅读
    请选择您浏览此新闻时的心情
    疑问
    疑问

    0
    难过
    难过

    0
    愤怒
    愤怒

    0
    喜欢
    喜欢

    0
    无聊
    无聊

    0
    鼓掌
    鼓掌

    0
    惊奇
    惊奇

    0
    骂人
    骂人

    0
    (521)
    (521)
    分享到: 投稿
    最新评论
    推荐信息
    资讯 国内 军事 体育 篮球 足球 娱乐 电影 电视 财经 经济 消费 科技 手机 电商 女性 情感 时尚
    文化 历史 文学 旅游 周边 出境 美食 家常 健康 房产 房价 调控 汽车 新车 品牌 教育 视频 博客
    关于优府网联系方式 网站地图服务条款
    版权所有:山西优府信息技术开发有限公司 Copyright 2008-2013 All rights reserved.
    增值电信业务经营许可证广播电视节目制作许可证固定刊物许可证网络文化经营许可证