当试图通过context.AttachTo(...)连接一个已经连接到给定上下文的对象时,我遇到以下错误:

ObjectStateManager中已存在具有相同密钥的对象.ObjectStateManager无法跟踪具有相同密钥的多个对象.

有没有一种方法可以实现以下目标:

context.IsAttachedTo(...)

干杯!

编辑:

Jason概述的扩展方法很接近,但它不适合我的情况.

我试图用另一个问题的答案中概述的方法做一些工作:

How do I delete one or more rows from my table using Linq to Entities *without* retrieving the rows first?

我的代码看起来有点像这样:

var user = new User() { Id = 1 };
context.AttachTo("Users", user);
comment.User = user;
context.SaveChanges();

这很好,除非我为那个用户做了其他事情,我使用相同的方法try 附加一个虚拟对象.这失败了,因为我之前已经附加了那个虚拟用户对象.我怎么能判断这个?

推荐答案

以下是我的结论,效果非常好:

public static void AttachToOrGet<T>(this ObjectContext context, string entitySetName, ref T entity)
    where T : IEntityWithKey
{
    ObjectStateEntry entry;
    // Track whether we need to perform an attach
    bool attach = false;
    if (
        context.ObjectStateManager.TryGetObjectStateEntry
            (
                context.CreateEntityKey(entitySetName, entity),
                out entry
            )
        )
    {
        // Re-attach if necessary
        attach = entry.State == EntityState.Detached;
        // Get the discovered entity to the ref
        entity = (T)entry.Entity;
    }
    else
    {
        // Attach for the first time
        attach = true;
    }
    if (attach)
        context.AttachTo(entitySetName, entity);
}

你可以这样称呼它:

User user = new User() { Id = 1 };
II.AttachToOrGet<Users>("Users", ref user);

这非常有效,因为它就像context.AttachTo(...),除了你可以使用我上面提到的ID技巧.最终,您会看到之前附着的对象或您自己的对象被附着.在上下文中调用CreateEntityKey可以确保它是好的、通用的,甚至可以在没有进一步编码的情况下使用复合键(因为EF已经可以为我们这样做了!).

Edit, twelve years later (Dec 2021)... oof!

以下是我在EF Core中使用的内容:

public static class EfExtensions
{
    public static T AttachToOrGet<T>(this DbContext context, Func<T,bool> predicate, Func<T> factory)
        where T : class, new()
    {
        var match = context.Set<T>().Local.FirstOrDefault(predicate);
        if (match == null)
        {
            match = factory();
            context.Attach(match);
        }

        return match;
    }
}

用法:

var item = db.AttachToOrGet(_ => _.Id == someId, () => new MyItem { Id = someId });

你可以重构它来使用实体键,但这已经足够让任何人都go 做了!

.net相关问答推荐

在数据网格中:如何在更改单元格 A 中的值后显示单元格 B 中的更改

仅使用 .NET GetBytes 方法转换有效字节而不创建问号

如何计算给定2个字符串的距离相似性度量?

单线程单元 - 无法实例化 ActiveX 控件

.gitignore 和 Visual Studio 项目:忽略 bin/Debug 目录但不忽略 bin/Release 目录

使用 Task.Factory.StartNew 传递方法参数

ILMerge 最佳实践

我可以使用 UriTemplate 将非字符串传递给 WCF RESTful 服务吗?

如何在 C# 中打开 Excel 文件?

如何将字符串列表数据绑定到 WPF/WP7 中的 ListBox?

如何在 C# 中创建 Word 文档?

InternalsVisibleTo 属性不起作用

如何退出所有正在运行的线程?

C#中的T是什么意思?

风格上的差异:IDictionary vs Dictionary

如何确定字符串是 C# 中的有效 IPv4 还是 IPv6 地址?

如何在 WPF 中的 Xaml 文件中添加注释?

String.Join 与 StringBuilder:哪个更快?

可以从 C# 调用 C++ 代码吗?

通过反射获取公共静态字段的值