简体   繁体   English

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

[英]Entity Framework virtual properties and database access for Id properties?

I have lot of interrelated entities in a project I'm working on, and I am using WCF to use them in several client applications. 我正在处理的项目中有很多相互关联的实体,我正在使用WCF在几个客户端应用程序中使用它们。 I soon realized that I was serializing half the data in the database with every call. 我很快就意识到每次调用我都会在数据库中序列化一半的数据。 I fixed the immediate issue but the system is still making lots of database calls, as my service layer objects iterate through all the nested objects in the data layer in their constructors. 我修复了当前的问题,但系统仍在进行大量的数据库调用,因为我的服务层对象遍历其构造函数中数据层中的所有嵌套对象。 Many times this is totally unnecessary, so I started to consider alternatives. 很多时候这是完全没必要的,所以我开始考虑替代方案。

If I specify the Id of my nested property then I don't believe the database call is made unless I access the properties of the nested object. 如果我指定我的嵌套属性的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; }
}

I can then use the constructor of my service object to determine whether to lazy load the nested objects something like this: 然后我可以使用我的服务对象的构造函数来确定是否延迟加载嵌套对象,如下所示:

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);
    }
}

Which works OK, except now I have an issue with my mock db context for my unit tests as I have to add the object and the id to each mock DbSet as I changed my service code to use the NestedObjectId property rather than the NestedObject.Id property 哪个工作正常,但现在我的单元测试的模拟数据库上下文存在问题,因为我必须将对象和id添加到每个模拟DbSet因为我更改了服务代码以使用NestedObjectId属性而不是NestedObject.Id属性

So I was wondering if the only virtual property that I accessed was the Id field if it would still make a database call for the whole of the object. 所以我想知道我访问的唯一虚拟属性是否仍然是Id字段,如果它仍然会对整个对象进行数据库调用。 Something like 就像是

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

This would solve my problem with my mocks, as the service code would always refer to the NestedObject.Id property and I may well end up doing this no matter what for ease of coding and maintainabilty, but I am curious as to whether or not this is the right approach. 这将解决我的NestedObject.Id问题,因为服务代码总是引用NestedObject.Id属性,无论编码和维护的NestedObject.Id性,我最终都会这样做,但我很好奇这是否是这个是正确的方法。

The main problem here is that your service API bleeds out your data access layer. 这里的主要问题是您的服务API会导致数据访问层流失。 Your service model very closely reassembles your data access model and therefore it is very hard to declare what data is needed for particular method and what data can be ommited. 您的服务模型非常密切地重新组合您的数据访问模型,因此很难声明特定方法需要哪些数据以及可以省略哪些数据。

I would suggest to redesign your service API so that every service method accepts minimal set of input parameters and returns minimal set of output parameters. 我建议重新设计您的服务API,以便每个服务方法都接受最小的输入参数集并返回最小的输出参数集。

Most likely you will have to introduce Request and Response objects for each service method. 您很可能必须为每个服务方法引入请求和响应对象。 It does not mean that you can not reuse any models in different methods. 这并不意味着您不能在不同方法中重用任何模型。 You have to identify data that make sense only when used together and extract those as separate classes. 您必须识别仅在一起使用时才有意义的数据,并将它们作为单独的类提取。

Then in every service method you can retrieve only the data that you need to create response. 然后,在每种服务方法中,您只能检索创建响应所需的数据。 You can do that by defining EF data projections and mapping them to response object either manually or by using libraries like AutoMapper. 您可以通过定义EF数据投影并将它们手动映射到响应对象或使用AutoMapper等库来实现。

For example: 例如:

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

If you write something like this, EF is actually smart enough to query only data needed. 如果你写这样的东西,EF实际上足够聪明,只能查询所需的数据。

When using lazy loading, EF access database when you access navigation property. 使用延迟加载时,访问导航属性时EF访问数据库。 When using eager loading, code will throw Null Reference exception if you try to access NestedDataObject without having loaded it first. 当使用预先加载时,如果您尝试访问NestedDataObject而不先加载它,代码将抛出Null Reference异常。

So I'm affraid what you are asking for is not possible. 所以我很害怕你所要求的是不可能的。

你可以使用include

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM