2015-10-07 71 views
4

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

如果我指定我的嵌套属性的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财产,我很可能最终会做这个不管是什么易于编程和maintainabilty的,但我好奇这是否是正确的方法。

+0

将您的虚拟属性更改为:public virtual Lazy NestedDataObject {get;组; }那么只有在访问属性时才会加载它。 –

+0

您需要数据实体和域(服务)实体之间的映射层。 –

+0

由于提出这个问题,我得出的结论是,所有相关的对象应该明确声明外键,并且嘲笑数据库上下文不是正确的测试方式。而是使用一个非常简单的存储库层,并使用服务层中的所有逻辑进行模拟。 –

回答

0

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

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

0

可以使用包括

.Include(x => x.myDataObject.SomeProperty) 
+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实际上是足够聪明,只查询所需要的数据。

+0

我明白你在做什么,但是我拥有很多相互关联的对象。大多数服务层对象具有某种形式的计算属性或派生属性,其中一些属性完全由其他对象派生而来。 –