实体框架6上下文不检索导航属性

时间:2014-02-06 15:45:39

标签: c# linq entity-framework lazy-loading

我发现了很多其他帖子,但他们面临着完全相同的问题。他们使用的代码略有不同。所以我觉得值得回顾一下。

我首先使用EF6代码,然后创建了一个具有一些导航属性的客户端实体。

我会发布相关代码,考虑还有一些属性和外键,但与问题无关。模型正在生成。

public class Client
{
    public Client()
    {
        JobsExperiences = new Collection<JobsExperience>();
        CapacitationCourses = new Collection<CapacitationCourse>();
        ScholarLevelDetails = new Collection<ScholarLevelDetail>();
        Relatives = new Collection<Relative>();
    }
    public long ClientID { get; set; }
    public virtual ICollection<ScholarLevelDetail> ScholarLevelDetails { get; set; }

    public virtual ICollection<JobsExperience> JobsExperiences { get; set; }
}

现在我创建了一个ClientServices类,我将所有获取或发送数据的方法放到数据库中。我有这个代码,随机工作,我会尝试清楚地解释。

    internal Client GetClient(string userId, bool lazyLoadingEnabled = true)
    {
        using (var context = new ApplicationDbContext())
        {
            context.Configuration.LazyLoadingEnabled=lazyLoadingEnabled;

            var client = (from _client in context.Client
                          where _client.ApplicationUserId == userId
                          select _client).FirstOrDefault();

            return client;
        }
    }

我的目标有些情况是只检索客户端属性,有时还包括所有属性,包括导航属性。

在我的控制器中,我有一条这样的行

var client = uuc.GetClient(user.Id, false);

或者

var client = uuc.GetClient(user.Id);

当我运行第一个句子时,导航属性被初始化但是所有都有Count = 0,即使我的DB有记录关联。我认为,如果禁用延迟加载,则表示启用了加载加载,但似乎没有。但是,导航属性中没有Load()方法来强制加载。

当我运行第二句时,导航属性抛出异常'client.ScholarLevelDetails'抛出了类型'System.ObjectDisposedException'的异常。这句话后面的一行抛出,盯着手表中的导航属性。但是,这是最奇怪的部分,如果我回到句子并调试步进方法,所有导航属性都会正确加载。

为什么一次运行代码的行为与运行单步方法的行为不同? 我假设using语句范围在导航属性加载之前完成,但是为什么禁用lay加载doe snot会检索它们呢? 我如何对此进行编码以保持一致的行为?

5 个答案:

答案 0 :(得分:6)

我在Linq中更改了查询代码Ihad。

    internal Client GetClient(string userId, bool lazyLoadingEnabled = true)
    {
        using (var context = new ApplicationDbContext())
        {
            context.Configuration.LazyLoadingEnabled = lazyLoadingEnabled;

            var client = context
                        .Client
                        .Include(s => s.ScholarLevelDetails)
                        .Include(s => s.JobsExperiences)
                        .Include(s => s.CapacitationCourses)
                        .Include(s => s.Relatives)
                        .FirstOrDefault(s => s.ApplicationUserId == userId);

            return client;
        }
    }

现在它有效。但是我仍然有一些问题需要与读者和同事讨论。

为什么简单的Linq不起作用? 为什么无论是否启用延迟加载都无关紧要,这段代码每次都能正常工作吗?

答案 1 :(得分:3)

问题是,在加载导航属性之前,您的上下文超出了范围。

要执行您想要的操作,您需要更改使用上下文的方式,或者只需使用您的查询语法通过表join急切加载您需要的实体如果使用lambda查询语法,则使用或通过.Include() lambda表达式。

    using (var context = new ApplicationDbContext())
    {
        context.Configuration.LazyLoadingEnabled=lazyLoadingEnabled;

        var client = (from _client in context.Client
                      where _client.ApplicationUserId == userId
                      select _client).FirstOrDefault();

        return client; //at this point, your context is gone, and no 
        //navigational properties will be loaded onto your client object, 
        //even if you try to navigate them. You may even get exceptions if
        //attempting to navigate to some properties.
    }

这是一个连接示例:

var client = (from _client in context.Client
              join t in context.Table on _client.Val equals t.val //this will eager load Table property on client.
              where _client.ApplicationUserId == userId
              select _client).FirstOrDefault();

答案 2 :(得分:2)

您应该对属性使用Include方法。

_context.Client.Include(c=>c.JobsExperiences) ... and all props like this

但是你最好不要使用延迟加载。 从方法返回后,原因上下文变为非活动状态。

答案 3 :(得分:1)

使用EF 6,我必须使用(lamba&#39; s和Client关键字不可用):

    using (var context = new SyntheticData.EF.DBContext())
    {
        var item = (from t in context.TEMPLATEs
                        .Include("DATASET")
                        .Include("COLUMNs")
                        .Include("SORTs")
                        .Include("FILTERs")
                    where t.USERID == identityname && t.ID == id select t).FirstOrDefault();
        return item;
    }

这填充了关系类,语法如下:

  • item.DATASET.xxx
  • item.COLUMNs [0] .XXX

&#34;使用(var context&#34;构造是一种很好的做法,因为它确保你与数据库的连接将被释放回池中。如果你不这样做,你最终可能会用尽繁忙系统的结论。

答案 4 :(得分:0)

以防这有助于某人我没有得到任何导航属性,我的问题似乎是EF没有正确地连接属性,因为我使用接口作为导航属性类型,我需要使用实际类型。除非有人知道如何使用注释或其他东西来告诉EF属性映射到的实际类型。