gpt4 book ai didi

c# - Entity Framework - 避免 "lookup"实体最初在另一个上下文中加载时获得添加状态

转载 作者:行者123 更新时间:2023-11-30 15:35:38 27 4
gpt4 key购买 nike

这是一些演示我的问题的测试代码:

using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using NUnit.Framework;

namespace EFGraphInsertLookup
{
public class GraphLookup
{
public int ID { get; set; }
public string Code { get; set; }
}

public class GraphChild
{
public int ID { get; set; }
public virtual GraphRoot Root { get; set; }
public virtual GraphLookup Lookup { get; set; }
}

public class GraphRoot
{
public int ID { get; set; }
public virtual ICollection<GraphChild> Children { get; set; }
}

public class TestDbContext : DbContext
{
public DbSet<GraphRoot> GraphRoots { get; set; }
public DbSet<GraphChild> GraphChildren { get; set; }
public DbSet<GraphLookup> GraphLookups { get; set; }

public TestDbContext()
{
GraphLookups.ToList();
}
}

public class TestDbInit : DropCreateDatabaseAlways<TestDbContext>
{
protected override void Seed(TestDbContext context)
{
base.Seed(context);
context.GraphLookups.Add(new GraphLookup { Code = "Lookup" });
context.SaveChanges();
}
}

[TestFixture]
public class Tests
{
[Test]
public void MainTest()
{
Database.SetInitializer<TestDbContext>(new TestDbInit());

var lookupCtx = new TestDbContext();
var firstLookup = lookupCtx.GraphLookups.Where(l => l.Code == "Lookup").Single();

var graph = new GraphRoot
{
Children = new List<GraphChild> { new GraphChild { Lookup = firstLookup } }
};
var ctx = new TestDbContext();
ctx.GraphRoots.Add(graph); // Creates a new lookup record, which is not desired
//ctx.GraphRoots.Attach(graph); // Crashes due to dupe lookup IDs
ctx.SaveChanges();

ctx = new TestDbContext();
graph = ctx.GraphRoots.Single();
Assert.AreEqual(1, graph.Children.First().Lookup.ID, "New lookup ID was created...");
}
}
}

我的愿望是让 GraphLookup 充当查找表,其中记录链接到其他记录,但记录永远不会通过应用程序创建。

我遇到的问题是当查找实体在不同的上下文中加载时,例如当它被缓存时。因此,保存记录的上下文不会跟踪该实体,并且当调用 GraphRoot DbSet 上的 Add 时,查找以 Added 的 EntityState 结束,但实际上它应该是 Unchanged。

如果我改为尝试使用附加,则会因重复键而导致崩溃,因为两个查找实体最终出现在上下文中。

解决这个问题的最佳方法是什么?请注意,我已经大大简化了实际问题。在我的实际应用程序中,这是通过位于 EF DBContext 之上的几个不同的存储库层、工作单元和业务服务类发生的。因此,我可以以某种方式在 DBContext 中应用的通用解决方案将是更受欢迎的。

最佳答案

如果您将现有实体(例如从缓存中)带入另一个 DbContext,您将必须显式管理实体状态。这导致了两个简单的结论:不要混合来自多个上下文的实体,除非你确实需要,并且当你这样做时,明确设置你附加的所有实体的状态 .

您可以尝试一种缓存方法。创建一个简单的缓存管理器类,可能是静态的。对于要缓存的每个实体类型,都有一个看起来像这样的 GetMyEntity(int myEntityId, DbContext context) 方法:

public MyEntity GetMyEntity(int entityId, MyContext context)
{
MyEntity entity;

// Get entity from context if it's already loaded.
entity = context.Set<MyEntity>().Loaded.SingleOrDefault(q => q.EntityId == entityId);

if (entity != null)
{
return entity;
}
else if (this.cache.TryGetValue("MYENTITY#" + entityId.ToString(), out entity)
{
// Get entity from cache if it's present. Adapt this to whatever cache API you're using.
context.Entry(entity).EntityState = EntityState.Unchanged;
return entity;
}
else
{
// Load entity if it's not in the context already or in the cache.
entity = context.Set<MyEntity>().Find(entityId);

// Add loaded entity to the cache. Adapt this to specify suitable rules for cache item expiry if appropriate.
this.cache["MYENTITY#" + entityId.ToString()] = entity;
return entity;
}
}

请原谅任何拼写错误,但希望您明白了。您可能会看到这可以被推广,因此您也不必为每个实体类型使用一种方法。

编辑:

以下代码可能有助于展示如何分离一切,除了您实际想要添加的实体。

// Add a single entity.
context.E1s.Add(new1);

var dontAddMeNow = (from e in context.ChangeTracker.Entries()
where !object.ReferenceEquals(e.Entity, new1)
select e).ToList();

foreach (var e in dontAddMeNow)
{
e.State = System.Data.EntityState.Unchanged; // Or Detached.
}

编辑2:

下面的代码展示了预加载引用数据如何解决您的问题。

E2 child = new E2 { Id = 1 };

context.Entry(child).State = System.Data.EntityState.Unchanged;

E1 new1 = new E1
{
Child = child
};

// Add a single entity.
context.E1s.Add(new1);

Debug.Assert(context.Entry(new1.Child).State == System.Data.EntityState.Unchanged);
Debug.Assert(context.Entry(new1).State == System.Data.EntityState.Added);

关于c# - Entity Framework - 避免 "lookup"实体最初在另一个上下文中加载时获得添加状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14648354/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com