简体   繁体   English

在c#EF6中返回相关集合的子集

[英]Return a subset of a related collection in c# EF6

I have a webservice that allows the user to query a give subset of data from a database. 我有一个Web服务,允许用户从数据库中查询给定的数据子集。 I will only know which fields the user wants at runtime. 我只会知道用户在运行时想要哪些字段。 It's quite easy to build a dynamic linq query to retrieve only the corresponding properties from the database for the fields in the object table itself, but how can I dynamically specify which fields I want to retrive in the related table ? 构建动态linq查询以从对象表本身中的字段中仅检索数据库中的相应属性非常容易,但是如何动态指定要在相关表中检索哪些字段? Sounds confusing, let me explain with a sample. 听起来令人困惑,让我用一个样本来解释。

So let's say I have a structure like: 所以我想说我的结构如下:

class User {
 public string Name {get; set;}
 public List<Role> Roles {get; set;}
}

class Role {
  public string RoleName {get; set;}
  public string RoleDescription {get; set;}
}

So User and Role are the objects used by EF6 in my code first databse table generation. 因此,用户和角色是EF6在我的代码第一个数据库表生成中使用的对象。

Now I have webservice that wants to get the username and the name of the roles from the database. 现在我有webservice想要从数据库中获取用户名和角色名称。 It will send a parameter like 它会发送一个参数

var requestData = "{fields: {'Name', 'Roles.RoleName'}}"`;

What I would like to do is only retrieve the RoleName field from the Roles collection, knowing another client might ask the Roles.RoleDescription only so I need to dynamically create the query. 我想要做的只是从Roles集合中检索RoleName字段,知道另一个客户端可能只询问Roles.RoleDescription所以我需要动态创建查询。 Ideally I should be able to generate this at the Select level on an IQueryable object in order to avoid getting a huge number of data from the database and only using one field. 理想情况下,我应该能够在IQueryable对象的Select级别生成它,以避免从数据库中获取大量数据并且只使用一个字段。

What I have tried so far: 到目前为止我尝试过的:

Using System.Linq.Dynamic to retrieve the properties of the User table. 使用System.Linq.Dynamic检索User表的属性。 Something like: 就像是:

var dynamicFields = GetFieldsFromRequestData(requestData); // results in "Name, Roles" 
var query = context.Set<User>().Select(dynamicFields);
query.Load();

Works like a charm. 奇迹般有效。 BUT will query all fields from the Roles collection. 但是将查询Roles集合中的所有字段。 I don't seem to be able to only select the Roles.RoleName column from the Roles table using the same strategy, which is what I want. 我似乎无法仅使用相同的策略从Roles表中选择Roles.RoleName列,这就是我想要的。

var query = context.Set<User>().Select("Name, Roles.RoleName");

Does not work. 不行。

I also tried using Linq.Expressions which requires specifying the objects types: 我也尝试使用Linq.Expressions,它需要指定对象类型:

class UserDTO {
 public string Name {get; set;}
 public List<RoleDTO> Roles {get; set;}
}

class RoleDTO {
 public string RoleName {get; set;}
}

then using Linq.Expressions I generate 然后使用我生成的Linq.Expressions

var generatedExpression = GetFieldsFromRequestDataLinq(requestData); //
results in an expression = (user => New UserDTO {Name = user.Name, Roles = user.Roles });
var query = context.Set<User>().Select(generatedExpression);

Works like a charm EF converts the objects in the Roles collection to RoleDTO objects. 像魅力一样工作EF将Roles集合中的对象转换为RoleDTO对象。

BUT this implies knowing in advance which fields will be queried in the Roles collection since I defined the RoleDTO type. 但这意味着事先知道在我定义RoleDTO类型后将在Roles集合中查询哪些字段。 Which is not what I want since I don't know the list of queried fields. 这不是我想要的,因为我不知道查询字段的列表。

So if someone has a nice way of solving this issue that would be awesome. 因此,如果有人有一个很好的方法来解决这个问题,那就太棒了。 I am open to AutoMapper solutions, to Newtonsoft JSON approaches, ... 我对AutoMapper解决方案,Newtonsoft JSON方法,...

Have been battling with this since 10 days ;-) 自10天以来一直在与此斗争;-)

you should be able to add properties to anonymous type on runtime: 您应该能够在运行时向匿名类型添加属性:

Add property to anonymous type after creation 创建后将属性添加到匿名类型

Utilitizing reflection the query could look like: 利用反射查询可能如下所示:

    var query = context.Set<User>().Select(p=>{ 
        var dto = new UserDTO{};

        parameterNames.foreach(pn =>{
            var value = p.GetField( pn ).GetValue (p, null);
            UserDTO.Add(parameter, value);
        });
        return dto;
    });

Based on the context you provided I would suggest to try out OData/GraphQL . 根据您提供的上下文,我建议尝试OData / GraphQL

It is usually flexible enough to be able to handle such kind of scenarios but can cause some other struggles. 它通常足够灵活,能够处理这种情况,但可能导致其他一些挣扎。

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

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