我有一个Web服务,允许用户从数据库查询给定数据子集。我只会知道用户在运行时需要哪些字段。构建动态linq查询以仅从数据库中检索对象表本身中的字段的对应属性非常容易,但是如何动态指定要在相关表中检索的字段呢?听起来令人困惑,让我用示例进行解释。
因此,假设我的结构如下:
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;}
}
因此,用户和角色是EF6在我的代码优先数据库表生成中使用的对象。
现在,我有一个Web服务,希望从数据库中获取用户名和角色名称。它将发送类似
的参数var requestData = "{fields: {'Name', 'Roles.RoleName'}}"`;
我只想从Roles集合中检索RoleName字段,因为知道另一个客户端可能只询问Roles.RoleDescription,所以我需要动态创建查询。理想情况下,我应该能够在IQueryable对象的Select级别上生成此文件,以避免从数据库中获取大量数据,而仅使用一个字段。
到目前为止,我已经尝试过:
使用System.Linq.Dynamic来检索User表的属性。像这样:
var dynamicFields = GetFieldsFromRequestData(requestData); // results in "Name, Roles"
var query = context.Set<User>().Select(dynamicFields);
query.Load();
像魅力一样工作。但将查询“角色”集合中的所有字段。我似乎无法仅使用相同的策略从Roles表中选择Roles.RoleName列。
var query = context.Set<User>().Select("Name, Roles.RoleName");
不起作用。
我还尝试使用Linq.Expressions,它需要指定对象类型:
class UserDTO {
public string Name {get; set;}
public List<RoleDTO> Roles {get; set;}
}
class RoleDTO {
public string RoleName {get; set;}
}
然后使用我生成的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);
像魅力EF一样工作,EF将Roles集合中的对象转换为RoleDTO对象。
但是,这意味着自从我定义RoleDTO类型以来,要预先知道要在Roles集合中查询哪些字段。这不是我想要的,因为我不知道查询的字段的列表。
因此,如果有人能很好地解决此问题,那就太好了。我愿意接受AutoMapper解决方案,Newtonsoft JSON方法,...
自10天以来一直在与之作战;-)
答案 0 :(得分:0)
您应该能够在运行时将属性添加到匿名类型:
Add property to anonymous type after creation
利用反射查询看起来像:
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;
});
答案 1 :(得分:0)
根据您提供的上下文,我建议尝试 OData / GraphQL 。
它通常足够灵活,能够处理这种情况,但会引起其他麻烦。