在变量中使用 C# Select
Use C# Select in variable
我有一个 linq select 部分,我经常使用它,所以我想知道是否有办法“重用”它,即将它放在某种变量中。
我的 linq 语句看起来有点像这样:
var today = DateTime.Now;
var tmp = _context.Student
.Where(b => b.Semester > 10)
.Select(b => new {
BName = b.Name,
SuperList = b.Seminars.SelectMany(sem => sem.DateFrom <= today && ......) // this is a superfancy and long subquery that I wanna reuse
});
因为我有一些其他的 linq 查询将使用完全相同的子查询,所以我尝试创建一个函数来为我提供这个子查询部分以供重用。但是,唉,它不起作用,查询没有抛出错误,但看起来好像子查询被完全忽略了:
var today = DateTime.Now;
var f1 = GetFancySubquery(today);
var tmp = _context.Student.Where(b => b.Semester > 10)
.Select(b => new {
BName = b.Name,
SuperList = f1.Invoke(b)
});
private Func<Student, List<SemesterSomethingDTO>> GetFancySubquery(DateTime tag)
{
Func<Student, List<SemesterSomethingDTO>> condition = s => s.Seminars.SelectMany(sem => ....).ToList();
return condition;
}
我觉得我很接近(或者可能不是)- 我做错了什么?我正在尝试做的事情是否可行?
我对你的实体一无所知。不过你可以试试属于code
var today = DateTime.Now;
var tmp = _context.Student.Include(i=>i.SuperList).Where(b => b.Semester > 10)
.Select(b => new {
BName = b.Name,
SuperList = b.Seminars.Where(sem => sem.DateFrom <= today && ......)
});
您似乎缺少用于确保加载研讨会数据的 .Include 语句。
如果你尝试它是否有效:
_context.Student.Include(s => s.Seminars)... // continue your query here
您可以阅读更多关于 .Include here.
此外,您可以将 Func 委托声明为变量,而不是从函数返回它。考虑来自 Microsoft's documentation 的这个例子:
// Declare a Func variable and assign a lambda expression to the
// variable. The method takes a string and converts it to uppercase.
Func<string, string> selector = str => str.ToUpper();
// Create an array of strings.
string[] words = { "orange", "apple", "Article", "elephant" };
// Query the array and select strings according to the selector method.
IEnumerable<String> aWords = words.Select(selector);
I feel like I'm close (or maybe not) - what am I doing wrong? Is what
I'm trying to do even possible?
你确实很接近,是的,这是可能的。
我认为对你来说最好的方法是为 IEnumerable(你要查询的列表)创建一个 extension method,因为你将在几个 re-using 查询部分,这就是为什么扩展方法可以帮助您保留内容 D.R.Y.
会是这样的:
class Program
{
static void Main(string[] args)
{
var today = DateTime.Now;
List<Student> students = new List<Student>();
// Not quite the same code as yours since I don't have all the classes
// but it's the same idea
var tmp = students
.Where(b => b.Name == "Student 1")
.Select(b => new
{
BName = b.Name,
SuperList = b.Courses.Select(course => course.Semester == 2).ToList()
});
// This is exactly the same query using and extension method
var tmp2 = students.FancyQuery("Student 1", 2);
}
}
public static class LinqExtension
{
/// <summary>
/// Extension method to query an IEnumerable<Student> by name and course semester
/// </summary>
/// <param name="query">Type that the method extends</param>
/// <param name="name">Student name</param>
/// <param name="semester">Course semester</param>
/// <returns>IEnumerable<QuerySelectResult> after filtering by name and semester</student></returns>
public static List<QuerySelectResult> FancyQuery(this IEnumerable<Student> query, string name, int semester)
{
return query.Where(b => b.Name == name)
.Select(b => new QuerySelectResult
{
BName = b.Name,
SuperList = b.Courses.Where(course => course.Semester == 2).ToList()
}).ToList();
}
}
public class Student
{
public string Name { get; set; }
public List<Course> Courses { get; set; }
}
public class Course
{
public string Name { get; set; }
public int Semester { get; set; }
}
public class QuerySelectResult
{
public string BName { get; set; }
public List<Course> SuperList { get; set; }
}
备注:
- 扩展 classes 和其中的方法必须是 public 静态的才能工作。据我所知。
- LinqExtension 的 FancyQuery 方法上的这个 IEnumerable
参数,指的是扩展所针对的类型。例如,您将无法将它与 IEnumerable. 一起使用
- 代码与您的不完全相同,但已尝试重现类似情况。
- LinqExtension 不应与我的代码示例位于同一 class 中。例如应该在 Extension 或 Helper 命名空间(文件夹)中。要在你的代码中的任何地方使用它,你应该插入一个带有它的命名空间的 using 语句并且它可以用于扩展你正在扩展的类型
如果有什么不清楚的地方,请尽管问:)
希望有用。
编辑 1:现在扩展方法没有整个查询(Where 和 Select 子句)。
Thank you very much! The problem here is: fancyQuery contains now the entire query. While I want only the subquery as reusable, the rest can look very different. so unfortunately this doesnt help me
how? it seems like I'm missing an important puzzlepiece here - how do I do it ?
class Program
{
static void Main(string[] args)
{
var today = DateTime.Now;
List<Student> students = new List<Student>();
// Not quite the same code as yours since I don't have all the classes
// but it's the same idea
var tmp = students
.Where(b => b.Name == "Student 1")
.Select(b => new
{
BName = b.Name,
SuperList = b.Courses.Select(course => course.Semester == 2).ToList()
});
// As you can see "students.Where(b => b.Name == "Student 1")" it's still and IEnumerable after the Where()
// clause is used, so the extension method can be used after it
var tmp2 = students.Where(b => b.Name == "Student 1").FancyQuery(2);
}
}
public static class LinqExtension
{
/// <summary>
/// Extension method to query an IEnumerable<Student> by name and course semester
/// </summary>
/// <param name="query">Type that the method extends</param>
/// <param name="name">Student name</param>
/// <param name="semester">Course semester</param>
/// <returns>IEnumerable<QuerySelectResult> after filtering by name and semester</student></returns>
public static List<QuerySelectResult> FancyQuery(this IEnumerable<Student> query, int semester)
{
// Took out the Where() clause from here, and left only the Select() one
return query.Select(b => new QuerySelectResult
{
BName = b.Name,
SuperList = b.Courses.Where(course => course.Semester == semester).ToList()
}).ToList();
}
}
编辑 2:仅适用于 SuperList 的扩展方法(IEnumerable 与我的 classes)
but fancyQuery adds the entire select - which I do not want. maybe next time I do not need BName but wanna query something else - the only thing I need is SuperList
您可以扩展任何您想要的类型,只需更改 return 和扩展方法的签名。现在它只在 SuperList 上使用,但可以与任何 IEnumerable 类型的对象一起使用(在本例中)
static void Main(string[] args)
{
var today = DateTime.Now;
List<Student> students = new List<Student>();
// Not quite the same code as yours since I don't have all the classes
// but it's the same idea
var tmp = students
.Where(b => b.Name == "Student 1")
.Select(b => new
{
BName = b.Name,
SuperList = b.Courses.Select(course => course.Semester == 2).ToList()
});
// Now the extension method is used only on SuperList
var tmp2 = students
.Where(b => b.Name == "Student 1")
.Select(b => new
{
BName = b.Name,
SuperList = b.Courses.FancyQuery(2)
});
}
}
public static class LinqExtension
{
/// <summary>
/// Extension method to query an IEnumerable<Student> by name and course semester
/// </summary>
/// <param name="query">Type that the method extends</param>
/// <param name="name">Student name</param>
/// <param name="semester">Course semester</param>
/// <returns>IEnumerable<QuerySelectResult> after filtering by name and semester</student></returns>
public static List<Course> FancyQuery(this IEnumerable<Course> query, int semester)
{
// Took out the Where() clause from here, and left only the Select() one
return query.Where(course => course.Semester == semester).ToList();
}
}
此类辅助函数需要扩展到生成的表达式树中。香草 EF 任何版本都不支持它。我建议使用 LINQKit 来完成这样的任务:
public static class DTOExtensions
{
[Expandable(nameof(GetFancySubqueryImpl))]
public static List<SemesterSomethingDTO> GetFancySubquery(this Student student, DateTime tag)
{
throw new InvalidOperationException();
}
private static Expression<Student, DateTime, List<SemesterSomethingDTO>> GetFancySubqueryImpl()
{
return (student, tag) => student.Seminars.SelectMany(sem => ....).ToList();
}
}
和用法:
var today = DateTime.Now;
var tmp = _context.Student
.Where(b => b.Semester > 10)
.AsExpandable() // activating LINQKit
.Select(b => new {
BName = b.Name,
SuperList = b.GetFancySubquery(today)
});
我有一个 linq select 部分,我经常使用它,所以我想知道是否有办法“重用”它,即将它放在某种变量中。
我的 linq 语句看起来有点像这样:
var today = DateTime.Now;
var tmp = _context.Student
.Where(b => b.Semester > 10)
.Select(b => new {
BName = b.Name,
SuperList = b.Seminars.SelectMany(sem => sem.DateFrom <= today && ......) // this is a superfancy and long subquery that I wanna reuse
});
因为我有一些其他的 linq 查询将使用完全相同的子查询,所以我尝试创建一个函数来为我提供这个子查询部分以供重用。但是,唉,它不起作用,查询没有抛出错误,但看起来好像子查询被完全忽略了:
var today = DateTime.Now;
var f1 = GetFancySubquery(today);
var tmp = _context.Student.Where(b => b.Semester > 10)
.Select(b => new {
BName = b.Name,
SuperList = f1.Invoke(b)
});
private Func<Student, List<SemesterSomethingDTO>> GetFancySubquery(DateTime tag)
{
Func<Student, List<SemesterSomethingDTO>> condition = s => s.Seminars.SelectMany(sem => ....).ToList();
return condition;
}
我觉得我很接近(或者可能不是)- 我做错了什么?我正在尝试做的事情是否可行?
我对你的实体一无所知。不过你可以试试属于code
var today = DateTime.Now;
var tmp = _context.Student.Include(i=>i.SuperList).Where(b => b.Semester > 10)
.Select(b => new {
BName = b.Name,
SuperList = b.Seminars.Where(sem => sem.DateFrom <= today && ......)
});
您似乎缺少用于确保加载研讨会数据的 .Include 语句。
如果你尝试它是否有效:
_context.Student.Include(s => s.Seminars)... // continue your query here
您可以阅读更多关于 .Include here.
此外,您可以将 Func 委托声明为变量,而不是从函数返回它。考虑来自 Microsoft's documentation 的这个例子:
// Declare a Func variable and assign a lambda expression to the
// variable. The method takes a string and converts it to uppercase.
Func<string, string> selector = str => str.ToUpper();
// Create an array of strings.
string[] words = { "orange", "apple", "Article", "elephant" };
// Query the array and select strings according to the selector method.
IEnumerable<String> aWords = words.Select(selector);
I feel like I'm close (or maybe not) - what am I doing wrong? Is what I'm trying to do even possible?
你确实很接近,是的,这是可能的。
我认为对你来说最好的方法是为 IEnumerable
会是这样的:
class Program
{
static void Main(string[] args)
{
var today = DateTime.Now;
List<Student> students = new List<Student>();
// Not quite the same code as yours since I don't have all the classes
// but it's the same idea
var tmp = students
.Where(b => b.Name == "Student 1")
.Select(b => new
{
BName = b.Name,
SuperList = b.Courses.Select(course => course.Semester == 2).ToList()
});
// This is exactly the same query using and extension method
var tmp2 = students.FancyQuery("Student 1", 2);
}
}
public static class LinqExtension
{
/// <summary>
/// Extension method to query an IEnumerable<Student> by name and course semester
/// </summary>
/// <param name="query">Type that the method extends</param>
/// <param name="name">Student name</param>
/// <param name="semester">Course semester</param>
/// <returns>IEnumerable<QuerySelectResult> after filtering by name and semester</student></returns>
public static List<QuerySelectResult> FancyQuery(this IEnumerable<Student> query, string name, int semester)
{
return query.Where(b => b.Name == name)
.Select(b => new QuerySelectResult
{
BName = b.Name,
SuperList = b.Courses.Where(course => course.Semester == 2).ToList()
}).ToList();
}
}
public class Student
{
public string Name { get; set; }
public List<Course> Courses { get; set; }
}
public class Course
{
public string Name { get; set; }
public int Semester { get; set; }
}
public class QuerySelectResult
{
public string BName { get; set; }
public List<Course> SuperList { get; set; }
}
备注:
- 扩展 classes 和其中的方法必须是 public 静态的才能工作。据我所知。
- LinqExtension 的 FancyQuery 方法上的这个 IEnumerable
参数,指的是扩展所针对的类型。例如,您将无法将它与 IEnumerable . 一起使用
- 代码与您的不完全相同,但已尝试重现类似情况。
- LinqExtension 不应与我的代码示例位于同一 class 中。例如应该在 Extension 或 Helper 命名空间(文件夹)中。要在你的代码中的任何地方使用它,你应该插入一个带有它的命名空间的 using 语句并且它可以用于扩展你正在扩展的类型
如果有什么不清楚的地方,请尽管问:)
希望有用。
编辑 1:现在扩展方法没有整个查询(Where 和 Select 子句)。
Thank you very much! The problem here is: fancyQuery contains now the entire query. While I want only the subquery as reusable, the rest can look very different. so unfortunately this doesnt help me
how? it seems like I'm missing an important puzzlepiece here - how do I do it ?
class Program
{
static void Main(string[] args)
{
var today = DateTime.Now;
List<Student> students = new List<Student>();
// Not quite the same code as yours since I don't have all the classes
// but it's the same idea
var tmp = students
.Where(b => b.Name == "Student 1")
.Select(b => new
{
BName = b.Name,
SuperList = b.Courses.Select(course => course.Semester == 2).ToList()
});
// As you can see "students.Where(b => b.Name == "Student 1")" it's still and IEnumerable after the Where()
// clause is used, so the extension method can be used after it
var tmp2 = students.Where(b => b.Name == "Student 1").FancyQuery(2);
}
}
public static class LinqExtension
{
/// <summary>
/// Extension method to query an IEnumerable<Student> by name and course semester
/// </summary>
/// <param name="query">Type that the method extends</param>
/// <param name="name">Student name</param>
/// <param name="semester">Course semester</param>
/// <returns>IEnumerable<QuerySelectResult> after filtering by name and semester</student></returns>
public static List<QuerySelectResult> FancyQuery(this IEnumerable<Student> query, int semester)
{
// Took out the Where() clause from here, and left only the Select() one
return query.Select(b => new QuerySelectResult
{
BName = b.Name,
SuperList = b.Courses.Where(course => course.Semester == semester).ToList()
}).ToList();
}
}
编辑 2:仅适用于 SuperList 的扩展方法(IEnumerable
but fancyQuery adds the entire select - which I do not want. maybe next time I do not need BName but wanna query something else - the only thing I need is SuperList
您可以扩展任何您想要的类型,只需更改 return 和扩展方法的签名。现在它只在 SuperList 上使用,但可以与任何 IEnumerable
static void Main(string[] args)
{
var today = DateTime.Now;
List<Student> students = new List<Student>();
// Not quite the same code as yours since I don't have all the classes
// but it's the same idea
var tmp = students
.Where(b => b.Name == "Student 1")
.Select(b => new
{
BName = b.Name,
SuperList = b.Courses.Select(course => course.Semester == 2).ToList()
});
// Now the extension method is used only on SuperList
var tmp2 = students
.Where(b => b.Name == "Student 1")
.Select(b => new
{
BName = b.Name,
SuperList = b.Courses.FancyQuery(2)
});
}
}
public static class LinqExtension
{
/// <summary>
/// Extension method to query an IEnumerable<Student> by name and course semester
/// </summary>
/// <param name="query">Type that the method extends</param>
/// <param name="name">Student name</param>
/// <param name="semester">Course semester</param>
/// <returns>IEnumerable<QuerySelectResult> after filtering by name and semester</student></returns>
public static List<Course> FancyQuery(this IEnumerable<Course> query, int semester)
{
// Took out the Where() clause from here, and left only the Select() one
return query.Where(course => course.Semester == semester).ToList();
}
}
此类辅助函数需要扩展到生成的表达式树中。香草 EF 任何版本都不支持它。我建议使用 LINQKit 来完成这样的任务:
public static class DTOExtensions
{
[Expandable(nameof(GetFancySubqueryImpl))]
public static List<SemesterSomethingDTO> GetFancySubquery(this Student student, DateTime tag)
{
throw new InvalidOperationException();
}
private static Expression<Student, DateTime, List<SemesterSomethingDTO>> GetFancySubqueryImpl()
{
return (student, tag) => student.Seminars.SelectMany(sem => ....).ToList();
}
}
和用法:
var today = DateTime.Now;
var tmp = _context.Student
.Where(b => b.Semester > 10)
.AsExpandable() // activating LINQKit
.Select(b => new {
BName = b.Name,
SuperList = b.GetFancySubquery(today)
});