我是Linq的新手。我一直在使用强类型数据集,但喜欢Linq创建对象的想法。
目前我使用数据集来检索从tblProducts和tblProductSettings连接数据的表。
这是一对多关系,因为产品为每个网站提供独特的tblSettings行的多个网站,但是假设每个网站的tblSettings总是有一行。
示例:
Select * from tblproducts, tblProductSettings where tblproducts.ProdID = tblProductSettings.ProdID and tblProductSettings.CreatorID = @CreatorID
数据集将提供一个很好的表来循环并显示带有设置的产品。
Linq会给我一个tblProducts对象,其中tblProductSettings作为集合。我不想每次都要循环一个集合来获取设置,因为这样,我相信为每个产品创建一个新的SQL查询并使访问设置变得痛苦。
我可以创建一个自定义对象tblProductsAll,但我可以填充此对象的唯一方法是...
var Product = from p in context.tblProducts
join ps in context.tblProductSettings on p.ProdID equals ps.ProdID
where p.CreatorID == 1 && ps.ProdCreatorDisplay == 1
select new tblProductsAll()
{
ProdTitle = p.ProdTitle,
ProdPrice = ps.ProdPrice
};
然后我可以将此模型传递给剃刀模板。
我的问题是......是否有更好的方法来设置属性?有20个或更多不同的属性,我不想继续设置它们,重复代码,每次我想要相同的对象,在网站中有一个不同的where子句。有没有办法阻止这种重复?即自动映射对象,或重用select新语句。
非常感谢任何帮助。
答案 0 :(得分:0)
由于您已标记此sql,我猜您正在使用实体框架。在这种情况下,您可以告诉linq它加载产品的设置而不显式指定连接。我假设您的产品与您的产品设置表有关系,该表通过产品实体的“设置”属性公开。
var allProducts = context.tblProducts
.Where(p => p.CreatorID == 1 && p.Settings.ProdCreatorDisplay == 1)
.Include(p = p.Settings)
.Select(p => CreateViewModelFromFullyPopulatedProductModel(p))
.ToList();
一旦加载完整设置,您就可以编写一个映射函数来为您进行映射。当然,这将加载所有产品的属性以及每个产品的设置。这可能是一个主要问题,具体取决于您加载了多少产品以及它们有多少未使用的属性,但从您的问题来看,听起来您已经为视图模型加载了大部分这些值。
答案 1 :(得分:0)
当有导航属性时,请使用它们!您的Product
实体具有导航属性ProductSettings
。这意味着查询可能如下所示:
var products = from p in context.Products
from ps in p.ProductSettings
where p.CreatorID == 1 && ps.ProdCreatorDisplay == 1
select new ProductsAll()
{
ProdTitle = p.ProdTitle,
ProdPrice = ps.FirstOrDefault().ProdPrice
};
(请注意,我固执地拒绝使用tbl
前缀)
但这并不能解决重复的代码问题。
输入AutoMapper。这是一个很好的小工具,它通过定义和执行对象之间的映射来从代码中删除样板属性复制语句。默认映射基于名称约定。例如。语句Mapper.CreateMap<Product,ProductDto>();
配置Product
和ProductDto
的所有同名属性之间的映射。 Mapper.Map<ProductDto>(product);
会从ProductDto
创建一个product
对象。
但是,您的ProductsAll
类的属性ProdPrice
来自ProductSettings
。如何处理?
这里可以使用AutoMapper的一个很好的功能。它还根据名称约定解析嵌套对象的属性。假设您的班级Product
有一个属性Title
,AutoMapper可以将其解析为目标对象中的属性ProductTitle
。让我们用它:
class ProductsAll
{
// ProductSetting should have a Product property.
public string ProductTitle { get; set; }
// Assuming ProductSetting has a property ProdPrice.
public decimal ProdPrice { get; set; }
}
...
Mapper.CreateMap<ProductSetting,ProductsAll>(); // ProductSetting!
var q = from ps in context.ProductSettings
where ps.Product.CreatorID == 1 && ps.ProdCreatorDisplay == 1;
// Now the magic!
var products = q.Project().To<ProductsAll>();
Project()
是IQueryable
上的扩展方法。好处是SQL语句只包含投影中使用的属性。如您所见,您可以定义一次映射,其余的则使用代码中的Project().To()
构造。
AutoMapper还有更多功能。这是一个快速的开始。