[英]Pass in an Expression to linq's Select
这是linq-to-sql
我有很多不同的类都在做相同的查询,但投影结果略有不同。 理想情况下,我希望能够在一个地方进行查询,并将投影传递给Select方法。 它适用于具体类型:
public void GetResults() {
var junk = db.SiteProducts.Select(Project());
}
public Expression<Func<DbEntities.SiteProduct, string>> Project() {
return p => p.ProductAlert;
}
但是当我尝试返回匿名类型时,它会失败
public void GetResults() {
var junk = db.SiteProducts.Select(Project());
}
public Expression<Func<DbEntities.SiteProduct, TResult>> Project<TResult>() {
return p => new { p.ProductAlert };
}
我完全理解为什么泛型类型推断在第二种情况下失败了。 但是有没有从头开始制作我自己的表达式的技巧 - 我错过了可以让这个工作?
IdeaBlade有一个ProjectionSelector
类,您可以使用它来抽象您的投影。 当您需要构建投影查询但不知道编译时涉及的类型时,可以创建ProjectionSelector
类的实例并在运行时传递类型信息。
该类和示例代码可以在这里找到:
创建动态“选择”,“SelectMany”和“GroupBy”子句
http://drc.ideablade.com/xwiki/bin/view/Documentation/dynamic-projection
这在编译时不起作用。 使用动态的东西,你可以使它工作当然。
一个简单的解决方案不是使用匿名类型而是使用定制的DTO类。 这样的DTO类只需要很少的行并且易于维护。 通常这是一个很好的解决方案。
这是一个有趣的问题。 我认为DTO可以帮助你,但是有一些限制和缺陷需要注意。 采取以下LINQPad示例:
class ProjectDTO
{
public string Name { get; set; }
public static Expression<Func<Project, ProjectDTO>> ToDTO = (e) => new ProjectDTO
{
Name = e.Name
};
public ProjectDTO() {}
public ProjectDTO(Project project)
{
Name = project.Name;
}
}
void Main()
{
Projects.Select(p => p.Name).Dump();
Projects.Select(ProjectDTO.ToDTO).Dump();
Projects.Select(p => new ProjectDTO(p)).Dump();
}
SQL生成:
SELECT [t0].[Name]
FROM [Project] AS [t0]
GO
SELECT [t0].[Name]
FROM [Project] AS [t0]
GO
SELECT [t0].[ProjectId], [t0].[Name], [t0].[Description], [t0].[DateCreated], [t0].[DateModified], [t0].[DateComplete], [t0].[CreatedBy]
FROM [Project] AS [t0]
如您所见,您无法使用复制构造函数来分配DTO的属性,因为这会强制从数据库中撤回整个对象。
如果您想扩展基础DTO并为更专业的数据视图添加更多属性,这也会略有限制,这意味着您最终可能会使用类似代码的多个Expression。
但是,我非常喜欢选项二,但我确信这个选项很可能仅限于单一类型的投影,请考虑以下示例:
var query = from p in Projects
join t in Tasks on p.ProjectId equals t.ProjectId
select ProjectDTO.ToDTO; //Can't be used like this
我不认为你可以在这种类型的查询语法中使用Expression。 一般来说,我认为不会有一个全面运作的解决方案。 您可能必须检查您的设计,看看您是否可以提供更少的投影,基于一些非常便宜的属性总是包含在查询中?
如果不使用Dynamic LINQ库或手动构建表达式树,我还想看看LINQ-SQL / LINQ-Entities是否可以创建动态选择。
如果我正确理解您的问题,您可以使用以下代码:
首先声明一种选择数据的方法,如下所示:
public List<TResult> FindAll<TResult>(Func<Regions, TResult> selector) where TResult : class
{
using (RepositoryDataContext = new DataClasses1DataContext())
{
return RepositoryDataContext.Regions.Select<Regions, TResult>(selector).ToList<TResult>();
}
}
那么你可以像这样构建你的select语句:
Func<Regions, SelectAllRegion> select = r => new SelectAllRegion
{
RegionID = r.RegionID,
RegionDescription = r.RegionDescription
};
我的SelectAllRegion
:
public class SelectAllRegion
{
public SelectAllRegion()
{
}
public int RegionID { get; set; }
public string RegionDescription { get; set; }
}
和地区是北翼的Region
表。我希望这对你有所帮助
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.