为什么我的code做懒加载我关闭了它在每一个可能的点即使经过? [英] Why is my code doing lazy loading even after I turned it off at every possible point?

查看:114
本文介绍了为什么我的code做懒加载我关闭了它在每一个可能的点即使经过?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想获得那有一个用户标识符,或者是等于0,或提供的值UserTest实体考试和测试实体。我有一些建议,但到目前为止都没有奏效。一种建议是通过让UserTest数据启动,另一个解决方案是通过获取考试数据开始。下面是我有当我用UserTests作为源起点。

I would like to get Exams and Test entities that have a UserTest entity with a UserId that is either equal to "0" or to a provided value. I had a number of suggestions but so far none have worked. One suggestion was to start by getting UserTest data and the other solution was to start by getting Exam data. Here's what I have when I used the UserTests as the source starting point.

我有以下的LINQ:

        var userTests = _uow.UserTests
            .GetAll()
            .Include(t => t.Test)
            .Include(t => t.Test.Exam)
            .Where(t => t.UserId == "0" || t.UserId == userId)
            .ToList();

当我检查 _uow.UserTests 与调试它是一个仓库,当我检查的DbContext configuration.lazyloading 然后将其设置为

When I check _uow.UserTests with the debugger it's a repository and when I check the dbcontext's configuration.lazyloading then it is set to false.

下面是我的类:

public class Exam
{
    public int ExamId { get; set; }
    public int SubjectId { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Test> Tests { get; set; }
}

public class Test
{
    public int TestId { get; set; }
    public int ExamId { get; set; }
    public string Title { get; set; }
    public virtual ICollection<UserTest> UserTests { get; set; }
}

public class UserTest
{
    public int UserTestId { get; set; }
    public string UserId { get; set; }
    public int TestId { get; set; }
    public int QuestionsCount { get; set; }
}

当我看着输出I看到的东西是这样的:

When I looked at the output I saw something like this:

[{"userTestId":2,
  "userId":"0",
  "testId":12,
  "test":{
      "testId":12,"examId":1,
      "exam":{
          "examId":1,"subjectId":1,
          "tests":[
               {"testId":13,"examId":1,"title":"Sample Test1",
                "userTests":[
                      {"userTestId":3,
                       "userId":"0",

请注意,它得到了 UserTest 对象,然后得到一个测试对象,然后考试对象。然而,考试对象包含一个测试集,然后转身走回再次回落,并得到不同的测试,这些内部的单元测试:

Note that it gets a UserTest object, then gets a test object and then an exam object. However the exam object contains a test collection and then it heads back down again and gets the different tests and the unit tests inside of those:

UserTest > 测试> 考试> 测试> UserTest

我已努力确保延迟加载是关闭的的调试告诉我它设置为。我使用的 EF6 的WebAPI ,但如果有差别,因为我在 C#级调试不能确定。

I have tried hard to ensure lazy loading is off and debug tell me it's set to false. I am using EF6 and WebAPI but not sure if that makes a difference as I am debugging at the C# level.

推荐答案

您无法避免逆导航属性是由EF,无论你负载渴望或延迟加载相关的实体填充。这种关系修正(如已被@Colin解释)是你不能关闭的功能。

You can't avoid that the inverse navigation properties are populated by EF, no matter if you load related entities with eager or lazy loading. This relationship fixup (as already explained by @Colin) is a feature you can't turn off.

您可以通过查询完成后作废的unwished逆导航属性解决的问题:

You could solve the problem by nullifying the unwished inverse navigation properties after the query is finished:

foreach (var userTest in userTests)
{
    if (userTest.Test != null)
    {
        userTest.Test.UserTests = null;
        if (userTest.Test.Exam != null)
        {
            userTest.Test.Exam.Tests = null;
        }
    }
}

不过,在我看来,你的设计缺陷就是你尝试序列的实体的代替的的数据传输对象的(DTO的),是专门给视图要发送数据的。通过使用DTO的你能避免你不想完全,也许你没有在你看来需要其他的实体属性相反的导航性能。你会定义三个DTO类,例如:

However, in my opinion the flaw of your design is that you try to serialize entities instead of data transfer objects ("DTOs") that are specialized to the view where you want to send the data to. By using DTOs you can avoid the inverse navigation properties that you don't want altogether and maybe other entity properties that you don't need in your view. You would define three DTO classes, for example:

public class ExamDTO
{
    public int ExamId { get; set; }
    public int SubjectId { get; set; }
    public string Name { get; set; }
    // no Tests collection here
}

public class TestDTO
{
    public int TestId { get; set; }
    public string Title { get; set; }
    // no UserTests collection here

    public ExamDTO Exam { get; set; }
}

public class UserTestDTO
{
    public int UserTestId { get; set; }
    public string UserId { get; set; }
    public int QuestionsCount { get; set; }

    public TestDTO Test { get; set; }
}

然后用投影加载数据:

And then use a projection to load the data:

var userTests = _uow.UserTests
    .GetAll()
    .Where(ut => ut.UserId == "0" || ut.UserId == userId)
    .Select(ut => new UserTestDTO
    {
        UserTestId = ut.UserTestId,
        UserId = ut.UserId,
        QuestionsCount = ut.QuestionsCount,
        Test = new TestDTO
        {
            TestId = ut.Test.TestId,
            Title = ut.Test.Title,
            Exam = new ExamDTO
            {
                ExamId = ut.Test.Exam.ExamId,
                SubjectId = ut.Test.Exam.SubjectId,
                Name = ut.Test.Exam.Name
            }
        }
    })
    .ToList();

您也可以通过定义只包含您需要的视图的所有属性的单一DTO类扁平化的对象图:

You could also "flatten" the object graph by defining only a single DTO class that contains all the properties you need for the view:

public class UserTestDTO
{
    public int UserTestId { get; set; }
    public string UserId { get; set; }
    public int QuestionsCount { get; set; }

    public int TestId { get; set; }
    public string TestTitle { get; set; }

    public int ExamId { get; set; }
    public int ExamSubjectId { get; set; }
    public string ExamName { get; set; }
}

投影将变得更加简单,看起来像这样:

The projection would become simpler and look like this:

var userTests = _uow.UserTests
    .GetAll()
    .Where(ut => ut.UserId == "0" || ut.UserId == userId)
    .Select(ut => new UserTestDTO
    {
        UserTestId = ut.UserTestId,
        UserId = ut.UserId,
        QuestionsCount = ut.QuestionsCount,
        TestId = ut.Test.TestId,
        TestTitle = ut.Test.Title,
        ExamId = ut.Test.Exam.ExamId,
        ExamSubjectId = ut.Test.Exam.SubjectId,
        ExamName = ut.Test.Exam.Name
    })
    .ToList();

通过使用DTO的你不仅可以避免逆导航属性的问题,但也遵循良好的安全习惯,从数据库白名单暴露的属性值作了明确规定。想象一下,你会增加测试访问密码属性设置为测试实体。有了您的code序列化即时加载全实体的所有属性的密码会得到系列化以及及以上线路运行。您不必更改任何code要做到这一点,并在最坏的情况下,你是在HTTP请求中暴露的密码,你会不知道。在当你定义DTO的一个新的实体属性将只与您的J​​SON数据,如果你明确地添加该属性的DTO类序列化的另一方面。

By using DTOs you do not only avoid the problems of inverse navigation properties but also follow good security practices to "white-list" the exposed property values from your database explicitly. Imagine you would add a test access Password property to the Test entity. With your code that serializes eagerly loaded full entities with all properties the password would get serialized as well and run over the wire. You don't have to change any code for this to happen and in the worst case you wouldn't be aware that you are exposing passwords in a HTTP request. On the other hand when you are defining DTOs a new entity property would only be serialized with your Json data if you add this property explicitly to the DTO class.

这篇关于为什么我的code做懒加载我关闭了它在每一个可能的点即使经过?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆