重新加载实体和所有导航属性关联-DbSet实体框架

本文关键字:实体 导航 属性 关联 框架 -DbSet 新加载 加载 | 更新日期: 2023-09-27 18:21:55

我在实体关联刷新方面遇到问题。当我得到一个这样的实体:

MyContext context = new MyContext();
Person myPerson = context.PersonSet.FirstOrDefault();
String myPersonName = myPerson.Name;
Address myPersonAddress = myPerson.Address;

我找了一个人,他有一个名为Address的关联,还有一个名叫Name的房产。如果我手动修改数据库中的数据,例如属性名称,我必须使用以下代码来重新加载我的实体:

context.Entry(myPerson).Reload();

我有了Name的新值。但如果我对Address也这样做,那就行不通了。我认为这是因为Address是一个关联财产。我需要刷新它。

如何强制重新加载地址关联(以及Person类中的所有其他关联)?

编辑:

在同样的情况下,一个人可以有多个地址。

MyContext context = new MyContext();
Person myPerson = context.PersonSet.FirstOrDefault();
String myPersonName = myPerson.Name;
List<Address> myPersonAddresses = myPerson.Addresses;

在这种情况下,它不是参考:

context.Entry(myPerson).Reference(p => p.Address).Load();
// Address will be populated with only the new address
// this isn't required because I use lazy loading

但是一个集合:

context.Entry(myPerson).Collection(p => p.Addresses).Load();
// Address will be populated with old value and new value

我需要使用这个来工作:

context.Entry(myPerson).Collection(p => p.Addresses).CurrentValue.Clear();
context.Entry(myPerson).Collection(p => p.Addresses).Load();

但对于我的所有导航属性来说,这样做似乎不是一个好的解决方案!

重新加载实体和所有导航属性关联-DbSet实体框架

如果不使用延迟加载,则必须显式加载新的Address(因为在最初加载Person时,必须显式地加载它(例如,使用Include)):

context.Entry(myPerson).Reload();
// If the person refers to another Address in the DB
// myPerson.Address will be null now
if (myPerson.Address == null)
    context.Entry(myPerson).Reference(p => p.Address).Load();
    // myPerson.Address will be populated with the new Address now

如果使用延迟加载,则不需要第二个代码块。尽管如此,只要您访问新myPerson.Address的属性,就会向数据库中获得一个新的查询(就像上面第二个代码块中有一个新查询一样),因为如果用户引用了数据库中的新地址,第一行就会将导航属性标记为未加载。

这种行为并不取决于您是否在模型类中暴露了外键。

似乎没有一种方法可以调用某个单一的魔术Reload方法,该方法可以在一次调用中重新加载和更新整个对象图(类似于没有一个Include来急于加载一个完整的对象图)。

如果它获得了一个条目,那么只有.Load()方法有帮助。

context.Entry(myPerson).Collection(p => p.Addresses).Load();

如果p.地址丢失了一个条目,则可以由刷新

((IObjectContextAdapter)CurrentContext(context)).ObjectContext.Refresh(RefreshMode.StoreWins, p.Addresses);

您需要使用Query()扩展来修改LINQ表达式。这是一个基于我个人代码的例子。在这段代码中,我使用myPerson对象的相关AddressType导航属性重新加载Addresses集合,并将结果放入SomeList:中

_DbContext.Entry<Person>(myPerson)
          .Collection(i => i.Adresses) // navigation property for Person
          .Query()
          .Include("AddressType")        // navigation property for Address
          .OrderBy(i => i.Name)
          .ThenBy(i => i.AddressType.AddressTypeName) // just an example
          .Select(i => new someClass
          {
              SoomeField1 = i.SomeField1,
              ...
          })
          .ToList()
          .ForEach(i => SomeList.Add(i)); // SomeList is a List<T>

在从dbContext读取对象之前,我已经使用Detach解决了这个问题。此方法允许我刷新对象的所有导航属性。我在这里描述了我的场景和解决方案的细节实体框架:重新加载新创建的对象/重新加载导航属性