Id属性的实体框架虚拟属性和数据库访问?

时间:2015-10-07 12:11:56

标签: c# entity-framework lazy-loading

我正在处理的项目中有很多相互关联的实体,我正在使用WCF在多个客户端应用程序中使用它们。我很快就意识到每次调用我都会在数据库中序列化一半的数据。我修复了当前的问题,但系统仍在进行大量的数据库调用,因为我的服务层对象遍历其构造函数中数据层中的所有嵌套对象。很多时候这是完全没必要的,所以我开始考虑替代方案。

如果我指定了我的嵌套属性的Id,那么除非我访问嵌套对象的属性,否则我不相信数据库调用。

public class MyDataObject
{    
    public Guid Id { get; set; }
    public string SomeProperty { get; set; }
    public Guid NestedDataObjectId { get; set; }
    [ForeignKey("NestedDataObjectId")]
    public virtual NestedDataObject NestedDataObject { get; set; }
}

然后我可以使用我的服务对象的构造函数来确定是否延迟加载嵌套对象,如下所示:

public class MyServiceObject
{
    public MyServiceObject(MyDataObject myDataObject, 
               bool includeNested = true)
    {
        Id = myDataObject.Id;
        SomeProperty = myDataObject.SomeProperty;
        NestedServiceObjectId = myDataObject.NestedDataObjectId;
        if (includeNested)
            NestedServiceObject = new NestedServiceObject(myDataObject.NestedDataObject,
                includeNested);
    }
}

哪个工作正常,但现在我的单元测试的模拟数据库上下文存在问题,因为我必须将对象和id添加到每个模拟DbSet,因为我更改了服务代码以使用{ {1}}属性而不是NestedObjectId属性

所以我想知道我访问的唯一虚拟属性是否仍然是Id字段,如果它仍然会对整个对象进行数据库调用。像

这样的东西
NestedObject.Id

这可以解决我的模拟问题,因为服务代码总是引用if (includeNested) { NestedServiceObject = new NestedServiceObject(myDataObject.NestedDataObject); } else { NestedServiceObject = new NestedServiceObject(myDataObject.NestedDataObject.Id); } 属性,不管编码和维护的简易性,我最终都会这样做,但我很好奇这是否是正确的方法。

3 个答案:

答案 0 :(得分:1)

这里的主要问题是您的服务API会导致您的数据访问层流失。您的服务模型非常接近地重新组合您的数据访问模型,因此很难声明特定方法需要哪些数据以及可以省略哪些数据。

我建议重新设计您的服务API,以便每个服务方法都接受最少的输入参数集并返回最小的输出参数集。

您很可能必须为每个服务方法引入请求和响应对象。这并不意味着您不能在不同方法中重用任何模型。您必须识别仅在一起使用时才有意义的数据,并将它们作为单独的类提取。

然后,在每种服务方法中,您只能检索创建响应所需的数据。您可以通过定义EF数据投影并手动或使用AutoMapper等库来将它们映射到响应对象来实现。

例如:

var result = db.Students
    .Select(x => new { Id = x.Id, FacultyName = x.Faculty.Name})
    .FirstOrDefault(x => x.Id == studentId);

如果你写这样的东西,EF实际上足够聪明,只能查询所需的数据。

答案 1 :(得分:0)

使用延迟加载时,在访问导航属性时访问EF数据库。 当使用预先加载时,如果您尝试访问NestedDataObject而没有先加载它,代码将抛出Null Reference异常。

所以我很害怕你所要求的是不可能的。

答案 2 :(得分:0)

您可以使用include

.Include(x => x.myDataObject.SomeProperty)