【问题标题】:Reload an entity and all Navigation Property Association- DbSet Entity Framework重新加载实体和所有导航属性关联 - DbSet 实体框架
【发布时间】:2012-02-23 06:32:32
【问题描述】:

我遇到了实体关联刷新问题。当我得到这样的实体时:

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();

但对我的所有导航属性执行此操作似乎不是一个好的解决方案!

【问题讨论】:

  • 你的意思是context.Entry(myPersonAddress).Reload() 有效吗?
  • 是的,这意味着它不起作用。因为这个方法只重新加载属性(=Name)而不是关联(=Address)
  • 啊,对不起,我误会了。因此,您不想重新加载同一 Address 实体的标量属性,而是重新加载与可能另一个 Address 实体的关系。嗯,好问题……
  • Person 是否具有用于 Address 导航属性的公开外键属性?
  • 如何公开外键属性?你的意思是 ?我的 .csdl 中有一个导航属性

标签: c# entity-framework ado.net entity-framework-4.1


【解决方案1】:

如果它获得一个条目,则只有您的 .Load() 方法有帮助。

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

如果p.Addresses丢失了一个条目,可以通过

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

【讨论】:

    【解决方案2】:

    如果您不使用延迟加载,则可以显式加载新的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 的属性,您就会获得对数据库的新查询(就像您在上面的第二个代码块中有一个新查询一样),因为如果第一行将导航属性标记为未加载person 指的是数据库中的一个新地址。

    此行为不取决于您是否在模型类中公开了外键。

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

    【讨论】:

    • 我同意,似乎没有办法调用单个方法重新加载。不幸的是,你在一个类中不仅有 Reference。你也可以收藏一些! (我编辑了我的问题以涵盖所有情况)
    • @Sam:我明白了。但我认为集合的逻辑是相同的(将Reference 替换为Collection)。不幸的是,您必须为每个导航属性单独执行此操作(就像您必须为每个导航属性使用 Include 以进行预加载一样)。
    • @Slauma dbContext.Entry(test).Collection(x =&gt; x.TestChildren).Load(); 没有重新加载实体框架核心的集合。有时间请看一下:stackoverflow.com/q/65723105/3850405
    【解决方案3】:

    在从 dbContext 读取对象之前,我使用 Detach 解决了这个问题。 此方法允许我刷新对象的所有导航属性。 我在这里描述了我的场景和解决方案的细节 Entity Framework: Reload newly created object / Reload navigation properties

    【讨论】:

      【解决方案4】:

      您需要使用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>
      

      【讨论】:

        猜你喜欢
        • 2011-08-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-16
        • 2013-04-10
        相关资源
        最近更新 更多