我有一個 linq 選擇部分,我經常使用它,所以我想知道是否有辦法“重用”它,即將它放在某種變數中。
我的 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;
}
我覺得我很接近(或者可能不是) - 我做錯了什么?我想要做的甚至可能嗎?
uj5u.com熱心網友回復:
此類輔助函式需要擴展為生成的運算式樹。vanilla 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)
});
uj5u.com熱心網友回復:
我對你的物體一無所知。但是你可以試試歸屬碼
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 && ......)
});
uj5u.com熱心網友回復:
我覺得我很接近(或者可能不是) - 我做錯了什么?我想要做的甚至可能嗎?
你確實很接近,是的,這是可能的。
我認為最好的方法是為 IEnumerable<Student> (您要查詢的串列)創建一個擴展方法,因為您將在多個部分中重復使用查詢,這就是擴展方法可以幫助您的原因保持干燥
它會是這樣的:
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; }
}
筆記:
- 擴展類和方法必須是公共靜態才能作業。據我所知。
- LinqExtension 的 FancyQuery方法上的這個 IEnumerable<Student>引數是指擴展所針對的型別。例如,您將無法將它與 IEnumerable<int> 一起使用。
- 代碼與您的代碼不完全相同,但試圖重現類似的情況。
- LinqExtension 不應與我的代碼示例屬于同一類。例如應該在 Extension 或 Helper 命名空間(檔案夾)中。要在代碼的任何地方使用它,您應該插入一個帶有其命名空間的 using 陳述句,并且它可以用于擴展您正在擴展的型別
如果有不清楚的地方,請詢問:)
希望它有用。
編輯 1:現在擴展方法沒有整個查詢(Where 和 Select 子句)。
非常感謝你!這里的問題是:fancyQuery 現在包含整個查詢。雖然我只希望子查詢可重用,但其余的看起來可能非常不同。所以不幸的是,這對我沒有幫助
如何?好像我在這里錯過了一個重要的拼圖 - 我該怎么做?
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<Course> 與我的類)
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
You can extend whatever type you want, just changed the the return and signature of the extension method. Now it's only used on SuperList, but can be used with any object of type IEnumerable<Course> (in this case)
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();
}
}
uj5u.com熱心網友回復:
看起來您缺少 .Include 陳述句以確保已加載研討會資料。
如果你嘗試它是否有效:
_context.Student.Include(s => s.Seminars)... // continue your query here
您可以閱讀更多關于 .Include的資訊。
此外,您可以將 Func 委托宣告為變數,而不是從函式中回傳它。考慮微軟檔案中的這個例子:
// 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);
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/422287.html
標籤:
下一篇:如何并排顯示串列和串列串列
