我还不太了解Linq2Sql,我想知道这个可能是常见的MVVM场景是否有诀窍。我有包含域模型的Linq2Sql数据上下文,但我从中获取自定义ViewModel对象的数据。
var query = from ord in ctx.Table_Orders
select new OrderViewModel()
{
OrderId = ord.OrderId,
OrderSum = ord.OrderSum,
OrderCurrencyId = ord.OrderCurrencyId,
OrderCurrencyView = ord.Currency.CurrencyText
};
所以我希望我的ViewModel从域对象中包含CurrencyId和从相关表中包含CurrencyText,以便在View中很好地显示它。
此代码效果很好。它使用join生成一个DB调用以获取CurrencyText。但该模型简化,真正的模型有更多的字段。我想使代码可重用,因为我有许多不同的查询,它返回相同的ViewModel。现在,对OrderViewModel的每一个小改动都需要大量的维护。
所以我将代码移动到OrderViewModel本身作为构造函数。
public OrderViewModel(Table_Order ord)
{
OrderId = ord.OrderId,
OrderSum = ord.OrderSum,
OrderCurrencyId = ord.OrderCurrencyId,
OrderCurrencyView = ord.Currency.CurrencyText
}
并称之为。
var query = from ord in ctx.Table_Orders
select new OrderViewModel(ord);
问题:联接已经消失数据库查询不再优化。现在我得到1 + N次调用数据库来获取每行的CurrencyText。
欢迎任何评论。也许我错过了不同的方法。
这就是 far 我可以独立完成的方式,以获得代码可重用性。我创建了一个完成工作并具有多个参数的函数。然后我需要明确地传递它与交叉实体线的所有内容。
var query = ctx.Table_Orders.Select(m =>
newOrderViewModel(m, m.Currency.CurrencyText));
再次优化数据库调用。但它仍然不觉得我在那里!对于这种情况你知道什么技巧?
编辑:最终解决方案 感谢@Muhammad Adeel Zahid的暗示,我得到了这个解决方案。 我为IQueryable创建了一个扩展
public static class Mappers
{
public static IEnumerable<OrderViewModel> OrderViewModels(this IQueryable<Table_Order> q)
{
return from ord in q
select new OrderViewModel()
{
OrderId = ord.OrderId,
OrderSum = ord.OrderSum,
OrderCurrencyId = ord.OrderCurrencyId,
OrderCurrencyView = ord.Currency.CurrencyText
};
}
}
现在我可以这样做以获取所有列表
var orders = ctx.Table_Order.OrderViewModels().ToList();
或者这样可以获得单个项目,或者其中任何内容与Where(x =&gt; ..)
var order = ctx.Table_Order
.Where(x => x.OrderId == id).OrderViewModels().SingleOrDefault();
这完全解决了这个问题。生成的SQL非常完美,翻译对象的代码是可重用的。像这样的方法应该适用于LINQ to SQL和LINQ to Entities。 (未经后者测试)再次感谢你@Muhammad Adeel Zahid
答案 0 :(得分:1)
通过让Linq2SQL急切地加载构建视图模型所需的引用entites,可以避免N + 1查询问题。这样,您可以构建一个对象列表(以及一些引用的对象)并使用它来构造所有内容。看看这个blog post。
但有一个警告:这种技术(为Linq2SQL数据上下文设置LoadOptions)每个数据上下文只能执行一次。如果需要使用不同的预先加载配置执行第二个查询,则必须重新初始化数据上下文。我使用围绕我的上下文的简单包装类来自动化它。
答案 1 :(得分:1)
每当我们查询数据库时,我们通常要求枚举对象(db中有多个记录),或者我们需要单个实体(db中的一个记录)。您可以在返回整个表的枚举的方法中编写映射代码,如
public IEnumerable<OrderViewModel> GetAllOrders()
{
return from ord in ctx.Table_Orders
select new OrderViewModel()
{
OrderId = ord.OrderId,
OrderSum = ord.OrderSum,
OrderCurrencyId = ord.OrderCurrencyId,
OrderCurrencyView = ord.Currency.CurrencyText
};
}
现在您可能希望过滤这些记录并返回另一个枚举,例如在currencyID
上public IEnumerable<OrderViewModel> GetOrdersByCurrency(int CurrencyID)
{
return GetAllOrders().Where(x=>x.CurrencyId == CurrencyID);
}
现在您可能还希望从所有这些视图模型中找到单个记录
public OrderViewModel GetOrder(int OrderID)
{
return GetAllOrders().SingleOrDefault(x=>x.OrderId == OrderID);
}
IEnumerable的优点在于它不断为查询添加条件,并且在需要之前不执行它。因此,除非您真的需要,否则您的整个表格都不会被加载,并且您将代码保存在一个位置。现在,如果ViewModel Mapping或查询本身有任何更改,则必须在GetAllOrders()方法中完成,其余代码将保持不变