实体框架虚拟属性和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
属性,我很可能最终这样做,无论如何易于编码和可维护性,但我很好奇这是否是正确的方法。
可以使用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而没有首先加载它,代码将抛出空引用异常。
所以恐怕你所要求的是不可能的。