在给定的示例中,使用LINQ查询相关表的最佳实践是什么?
在给定的示例中,使用LINQ查询相关表的最佳实践是什么?
假设我正在从多个相关的表中生成一个视图模型。以以下方式查询的优点/差异/缺点是什么:
第一种方式:
var enrollment = db.enrollment .Include(d => d.cohort.OldCourses.OldCourseSections.Select(f => f.OldCoursePages)) .Include(d => d.OldProgress) .FirstOrDefault(b => b.UserID == currentuser && b.cohort.OldCourses.Titleabbrev == courseabbrev); var viewModel = new OldSectionViewModel(); viewModel.OldCourseTitle = enrollment.cohort.OldCourses.OldCourseTitle; viewModel.OldCourseSec_title = enrollment.cohort.OldCourses.OldCourseSections.FirstOrDefault(f => f.OldCourseSec_abbrev == secabbrev).OldCourseSec_title; viewModel.Meta = enrollment.cohort.OldCourses.Meta; viewModel.Titleabbrev = enrollment.cohort.OldCourses.Titleabbrev; viewModel.OldCourseSec_abbrev = enrollment.cohort.OldCourses.OldCourseSections.FirstOrDefault(f => f.OldCourseSec_abbrev == secabbrev).OldCourseSec_abbrev; viewModel.progress = currentprogress; viewModel.pages = enrollment.cohort.OldCourses.OldCourseSections.FirstOrDefault(f => f.OldCourseSec_abbrev == secabbrev).OldCourse_Page_Total; viewModel.EnrollmentID = enrollment.EnrollmentID; viewModel.OldCourseSectionID = enrollment.cohort.OldCourses.OldCourseSections.FirstOrDefault(f => f.OldCourseSec_abbrev == secabbrev).OldCourseSectionID; viewModel.OldCoursePage_title = enrollment.cohort.OldCourses.OldCourseSections.FirstOrDefault(f => f.OldCourseSec_abbrev == secabbrev).OldCoursePages.FirstOrDefault(g => g.OldCoursePage_Order == currentprogress).OldCoursePage_title; viewModel.OldCoursePage_HTML = enrollment.cohort.OldCourses.OldCourseSections.FirstOrDefault(f => f.OldCourseSec_abbrev == secabbrev).OldCoursePages.FirstOrDefault(g => g.OldCoursePage_Order == currentprogress).OldCoursePage_HTML; viewModel.OldCoursePage_Order = enrollment.cohort.OldCourses.OldCourseSections.FirstOrDefault(f => f.OldCourseSec_abbrev == secabbrev).OldCoursePages.FirstOrDefault(g => g.OldCoursePage_Order == currentprogress).OldCoursePage_Order;
或者以下方式:
var viewModel = db.enrollment .Where(b => b.UserID == currentuser && b.cohort.OldCourses.Titleabbrev == courseabbrev) .Select(x => new OldSectionViewModel { OldCourseTitle = x.cohort.OldCourses.OldCourseTitle, OldCourseSec_title = x.cohort.OldCourses.OldCourseSections.FirstOrDefault(f => f.OldCourseSec_abbrev == secabbrev).OldCourseSec_title, Meta = x.cohort.OldCourses.Meta, Titleabbrev = x.cohort.OldCourses.Titleabbrev, OldCourseSec_abbrev = x.cohort.OldCourses.OldCourseSections.FirstOrDefault(f => f.OldCourseSec_abbrev == secabbrev).OldCourseSec_abbrev, progress = currentprogress, pages = x.cohort.OldCourses.OldCourseSections.FirstOrDefault(f => f.OldCourseSec_abbrev == secabbrev).OldCourse_Page_Total, EnrollmentID = x.EnrollmentID, OldCourseSectionID = x.cohort.OldCourses.OldCourseSections.FirstOrDefault(f => f.OldCourseSec_abbrev == secabbrev).OldCourseSectionID, OldCoursePage_title = x.cohort.OldCourses.OldCourseSections.FirstOrDefault(f => f.OldCourseSec_abbrev == secabbrev).OldCoursePages.FirstOrDefault(g => g.OldCoursePage_Order == currentprogress).OldCoursePage_title, OldCoursePage_HTML = x.cohort.OldCourses.OldCourseSections.FirstOrDefault(f => f.OldCourseSec_abbrev == secabbrev).OldCoursePages.FirstOrDefault(g => g.OldCoursePage_Order == currentprogress).OldCoursePage_HTML, OldCoursePage_Order = x.cohort.OldCourses.OldCourseSections.FirstOrDefault(f => f.OldCourseSec_abbrev == secabbrev).OldCoursePages.FirstOrDefault(g => g.OldCoursePage_Order == currentprogress).OldCoursePage_Order, }).Single();
假设'currentprogress'是在其他地方设置的整数。在我看来,第二个查询会稍微更有效,因为我只加载所需的特定字段,而第一个查询则加载整个表。然而,我对这些东西的理解非常基础,我很想听到一个真正了解的人从实质上哪个更有效以及为什么的观点?
这两个查询都符合贪婪加载吗?
在使用LINQ查询相关表时,存在以下两种方法。第一种方法是在一个查询中包含所有相关表。第二种方法是生成N+1个查询。
通常情况下,应避免出现N+1查询的情况,但这也很大程度上取决于数据的情况。一次查询这么多相关表会导致大量数据的传输,而且使用这些连接意味着会传输所有相关项。例如,如果您只需要每个表的第一个相关项,那么通过进行一次大查询,您将返回大量永远不会使用的数据。
进行N+1个查询可能意味着向服务器发送大量查询,但是“大量”的定义是可变的。如果最终需要发送10-20个相对较小的查询,并且您拥有具有足够资源的良好数据库服务器实例,那么这可能不会对性能造成太大影响,因此最好只选择实际需要的数据。
另外,您还可以使用内存缓存,这样您可能只需要每小时运行一次这些查询或者每天运行一次。您只需要研究每种选项的情况,并确定哪种方法最高效/最合理。
然而,这取决于情况。Entity Framework会自动包含在Select调用中的某些项,假设它确定需要这些数据并且可以基于现有数据创建适当的连接。但这不是您应该依赖的东西。
,选择如何查询相关表取决于数据量和实际需求。需要综合考虑性能和资源利用的问题,选择最适合的方法。
在使用LINQ查询相关表时,最佳实践是什么?给定以下示例,这个问题出现的原因是什么,以及解决方法是什么?
问题原因:在给定的示例中,查询涉及多个相关表,而且在选择结果时需要加载一些变量。但是,原始代码中的查询语句无法正确加载这些变量,导致出现错误。
解决方法:为了在选择结果时加载变量,需要使用大括号和return关键字。下面是一个更简单的示例,说明了如何使用这种语法。这样可以在匿名对象或类对象的返回之前运行代码。
public class Item { public int Price { get; set; } = 0; public string Name { get; set; } = ""; } static void Main(string[] args) { var Collection = new List- (); var itemPrices = Collection.Select(item => { var x = 10; var y = item.Price; return new { ItemName = item.Name, ItemPrice = x * y }; }).ToList(); itemPrices.ForEach(itemData => { Console.WriteLine(itemData.ItemName + " " + itemData.ItemPrice.ToString()); }); }
在给定的示例中,可以通过将查询结果转换为List后再使用.Select()方法来解决问题。修改后的代码如下:
var viewModel = db.enrollment .Where(b => b.UserID == currentuser && b.cohort.OldCourses.Titleabbrev == courseabbrev) .ToList() .Select(x => { var oldCourseSection = x.cohort.OldCourses.OldCourseSections.FirstOrDefault(f => f.OldCourseSec_abbrev == secabbrev); var oldCourseSectionPage = oldCourseSection.OldCoursePages.FirstOrDefault(g => g.OldCoursePage_Order == currentprogress); return new OldSectionViewModel() { OldCourseTitle = x.cohort.OldCourses.OldCourseTitle, OldCourseSec_title = oldCourseSection.OldCourseSec_title, Meta = x.cohort.OldCourses.Meta, Titleabbrev = x.cohort.OldCourses.Titleabbrev, OldCourseSec_abbrev = oldCourseSection.OldCourseSec_abbrev, progress = currentprogress, pages = oldCourseSection.OldCourse_Page_Total, EnrollmentID = x.EnrollmentID, OldCourseSectionID = oldCourseSection.OldCourseSectionID, OldCoursePage_title = oldCourseSectionPage.OldCoursePage_title, OldCoursePage_HTML = oldCourseSectionPage.OldCoursePage_HTML, OldCoursePage_Order = oldCourseSectionPage.OldCoursePage_Order, }; }) .Single();
这样修改后的代码可以正确加载变量并解决问题。