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

本文关键字:属性 数据库 访问 Id 框架 虚拟 实体 | 更新日期: 2023-09-27 18:16:30

我在一个项目中有很多相互关联的实体,我正在使用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,因为我改变了我的服务代码使用NestedObjectId属性,而不是NestedObject.Id属性

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

if (includeNested)
{
    NestedServiceObject = new NestedServiceObject(myDataObject.NestedDataObject);
}
else
{
    NestedServiceObject = new NestedServiceObject(myDataObject.NestedDataObject.Id);
} 

这将解决我的模拟问题,因为服务代码将始终引用NestedObject.Id属性,我很可能最终这样做,无论如何易于编码和可维护性,但我很好奇这是否是正确的方法。

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

可以使用include

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

这里的主要问题是您的服务API溢出了您的数据访问层。您的服务模型非常紧密地重组了您的数据访问模型,因此很难声明特定方法需要哪些数据以及可以提交哪些数据。

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

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

那么在每个服务方法中,您只能检索创建响应所需的数据。您可以通过定义EF数据投影并将其映射到响应对象来实现这一点,可以手动或使用像AutoMapper这样的库。

例如:

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

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

当使用延迟加载时,EF在访问导航属性时访问数据库。当使用急切加载时,如果您试图访问NestedDataObject而没有首先加载它,代码将抛出空引用异常。

所以恐怕你所要求的是不可能的。

相关文章: