在单个LINQ语句中加载父记录及其子记录
我知道对数据库进行两次点击就可以轻松完成这项工作,但我一直在尝试使用一条LINQ语句来加载order by ID及其order项,同时将它们转换为ViewModel对象:在单个LINQ语句中加载父记录及其子记录,linq,linq-to-sql,eager-loading,Linq,Linq To Sql,Eager Loading,我知道对数据库进行两次点击就可以轻松完成这项工作,但我一直在尝试使用一条LINQ语句来加载order by ID及其order项,同时将它们转换为ViewModel对象: var query = from orderLine in db.PurchaseOrderLines where orderLine.PurchaseOrderId == id orderby orderLine.Id group orderLine b
var query = from orderLine in db.PurchaseOrderLines
where orderLine.PurchaseOrderId == id
orderby orderLine.Id
group orderLine by orderLine.PurchaseOrder into grouped
select new PurchaseOrderViewModel
{
Id = grouped.Key.Id,
PlacedDateTime = grouped.Key.PlacedDateTime,
Reference = grouped.Key.OrderReference,
StatusId = grouped.Key.PurchaseOrderStatusId,
Status = grouped.Key.PurchaseOrderStatus.Description,
Supplier = grouped.Key.Supplier.Name,
SupplierId = grouped.Key.SupplierId,
OrderLines = grouped.Select(row => new PurchaseOrderLineViewModel
{
Id = row.Id,
PartNumber = row.Product.PartNumber,
ProductDescription = row.Product.Description,
Quantity = row.Quantity
})
};
但是,查询类型为System.Data.Objects.ObjectQuery,尝试迭代结果会引发异常:
System.InvalidOperationException was unhandled by user code
Message=Sequence contains no elements
Source=System.Core
StackTrace:
at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
at System.Data.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__3[TResult](IEnumerable`1 sequence)
at System.Data.Objects.ELinq.ObjectQueryProvider.ExecuteSingle[TResult](IEnumerable`1 query, Expression queryRoot)
at System.Data.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute[S](Expression expression)
at System.Linq.Queryable.Single[TSource](IQueryable`1 source)
at MyApp.Controllers.PurchaseOrderController.Details(Int32 id) in E:\Code\WCs\MyApp\MyApp\Controllers\PurchaseOrderController.cs:line 69
at lambda_method(Closure , ControllerBase , Object[] )
at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12()
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
InnerException:
我做错了什么?我这样做是不是犯了错误
非常感谢。您有几个选项可以强制在LINQ to SQL中进行即时加载。如果不知道您是如何执行查询的,或者是否正在实现分页等等,就很难说了 在现有查询中,我要尝试的第一件事是在执行查询时强制订单行进入新列表,如下所示:
OrderLines = grouped.Select(row => new PurchaseOrderLineViewModel
{
Id = row.Id,
PartNumber = row.Product.PartNumber,
ProductDescription = row.Product.Description,
Quantity = row.Quantity
}).ToList()
如果这行得通,那就简单了
另一种方法是使用DataLoadOptions类。这是在LINQtoSQL中实现即时加载的常用方法
var loadOptions = new DataLoadOptions();
loadOptions.LoadWith<PurchaseOrder>(p => p.PurchaseOrderLines);
db.LoadOptions = loadOptions;
唯一需要注意的是,在使用上下文之前,需要设置datacontext的LoadOptions属性。如果您在短期内以推荐的方式使用上下文(每个操作一个实例),这应该不会是一个问题,但是这种使用模式似乎不像预期的那样普遍。如果您创建一个datacontext并将其传递或保留,那么这可能会给您带来问题。您有几个选项可以强制在LINQ to SQL中进行即时加载。如果不知道您是如何执行查询的,或者是否正在实现分页等等,就很难说了 在现有查询中,我要尝试的第一件事是在执行查询时强制订单行进入新列表,如下所示:
OrderLines = grouped.Select(row => new PurchaseOrderLineViewModel
{
Id = row.Id,
PartNumber = row.Product.PartNumber,
ProductDescription = row.Product.Description,
Quantity = row.Quantity
}).ToList()
如果这行得通,那就简单了
另一种方法是使用DataLoadOptions类。这是在LINQtoSQL中实现即时加载的常用方法
var loadOptions = new DataLoadOptions();
loadOptions.LoadWith<PurchaseOrder>(p => p.PurchaseOrderLines);
db.LoadOptions = loadOptions;
唯一需要注意的是,在使用上下文之前,需要设置datacontext的LoadOptions属性。如果您在短期内以推荐的方式使用上下文(每个操作一个实例),这应该不会是一个问题,但是这种使用模式似乎不像预期的那样普遍。如果您创建一个datacontext并将其传递或保留,那么这可能会给您带来问题