简体   繁体   English

实体框架ObjectQuery.Include()

[英]Entity Framework ObjectQuery.Include()

I have an object with two objects as properties ( User , PrimaryNode ), both could potentially be null, see below: 我有一个对象,其中有两个对象作为属性( UserPrimaryNode ),都可能为null,请参见下文:

public class Item
{
    [Key]
    public int ItemId { get; set; }
    public string ItemName { get; set; }
    public Node PrimaryNode { get; set; }
    public User User { get; set; }
}

I'm using Entity Framework 6 to populate the Item object and using chained includes to populate the PrimaryNode and User objects within it. 我正在使用Entity Framework 6填充Item对象,并使用链式包含在其中填充PrimaryNodeUser对象。

When the first chained Include has a null object then the whole object returns as null, for example: 当第一个链接的Include具有空对象时,则整个对象将返回空值,例如:

using (var db = new MyContext())
{
    var item = db.Items.Include(i => i.User).Include(n => n.PrimaryNode).FirstOrDefault(i => i.ItemId == id);
}

If in the above example i.User is null then the item variable is null. 如果在上面的示例中i.User为null,则item变量为null。 Whats the best way of populating both the sub-objects in a way that if a sub-object is null then the parent object and the other sub-object will still be populated? 以某种方式填充两个子对象的最佳方法是:如果一个子对象为null,则仍将填充父对象和另一个子对象?

I think it would be better if you use Lazy loading int his situation. 我认为如果您在他的情况下使用Lazy loading会更好。 Just make the User and PrimaryNode virtual: 只需将UserPrimaryNode虚拟:

public class Item
{
   [Key]
   public int ItemId { get; set; }
   public string ItemName { get; set; }
   public virtual Node PrimaryNode { get; set; }
   public virtual User User { get; set; }
}

And then: 然后:

var db = new MyContext();
var item = db.Items.FirstOrDefault(i => i.ItemId == id);

I don't think your issue is due to the Include calls. 我认为您的问题不是由于Include通话引起的。 According with the documentation : 根据文档

This extension method calls the Include(String) method of the IQueryable source object, if such a method exists. 如果存在这样的方法,则此扩展方法将调用IQueryable源对象的Include(String)方法。 If the source IQueryable does not have a matching method, then this method does nothing . 如果源IQueryable没有匹配方法,则此方法不执行任何操作

In other words is going to be translated to: 换句话说,将被翻译为:

 var item = db.Items.Include("User").Include("PrimaryNode").FirstOrDefault(i => i.ItemId == id);

My question is, are you sure you have an Item with that id properly related with existing rows in Users and PrimaryNodes tables in your DB?. 我的问题是,您确定您有一个ID与数据库中UsersPrimaryNodes表中的现有行正确相关的Item吗? When you call Include method at the end is going to be translated to a join, so if the FK of your relationship doesn't match with the PK that reference, your query should not return what you are expecting. 当您在最后调用Include方法将转换为联接时,因此,如果关系的FK与该引用的PK不匹配,则查询不应返回期望的结果。

Anyways, if you want to try another variant to load related properties you can use Explicit Loading : 无论如何,如果您想尝试另一个变体来加载相关属性,则可以使用Explicit Loading

var item = db.Items.FirstOrDefault(i => i.ItemId == id);
context.Entry(item).Reference(p => p.PrimaryNode).Load(); 
context.Entry(item).Reference(p => p.User).Load();

As others have mentioned, I think your issue is not due to the Includes. 正如其他人所提到的,我认为您的问题并非归因于Includes。 However, I think the following method has value. 但是,我认为以下方法有价值。 It is functionally equivalent to what you are already doing with the chained includes, but I think it has several benefits including making the intention of the code clear to the user. 它在功能上等同于您已经对链接的include所做的事情,但是我认为它具有许多好处,包括使用户清楚代码的意图。

The includes can be placed in Extension methods: 包括可以放在扩展方法中:

using System.Data.Entity;
using System.Linq;

namespace Stackoverflow
{
    public static class EntityExtensions
    {
        public static IQueryable<Item> IncludePrimaryNode(this IQueryable<Item> query)
        {
            // eager loading if this extension method is used
            return query.Include(item => item.PrimaryNode);
        }

        public static IQueryable<Item> IncludeUser(this IQueryable<Item> query)
        {
            // eager loading if this extension method is used
            return query.Include(item => item.User);
        }
    }
}

Then, you can use the extensions as follows: 然后,您可以按以下方式使用扩展名:

using (var db = new MyContext())
{
    var itemQuery = db.Items.IncludeUser();

    itemQuery = itemQuery.IncludePrimaryNode();

    var item = itemQuery.FirstOrDefault(i => i.Id == 1);
}

It's just another way of doing the same thing, but I like the clarity it adds to the code. 这只是做同一件事的另一种方式,但是我喜欢它为代码增加的清晰度。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM