我有 2 个表 Products 和 ProductDetails。Products 包含有关我的库存的所有信息,ProductDetails 用于允许在产品价格更改生效之前在系统中更新它们。
我正在尝试编写一个简单的查询,该查询返回所有产品,如果在 CommenceDate 小于或等于当前日期的 ProductDetails 中找到匹配的行,则还更新产品的成本和价格。到目前为止我所拥有的是:
var products = from p in Products
from pd in ProductDetails
.Where(pd => pd.ProductID == p.ID && pd.CommenceDate <= DateTime.Now)
.DefaultIfEmpty()
where p.InUse == true
select p;
Run Code Online (Sandbox Code Playgroud)
我首先认为我可以通过在选择中声明一个新产品来实现我所追求的,例如:
var products = from p in Products
from pd in ProductDetails
.Where(pd => pd.ProductID == p.ID && pd.CommenceDate <= DateTime.Now)
.DefaultIfEmpty()
where p.InUse == true
select new Product {
ID = p.ID,
Description = p.Description,
....
Cost = pd.Cost.HasValue ? pd.Cost : p.Cost,
Price = pd.Price.HasValue ? pd.Price : p.Price,
...
};
Run Code Online (Sandbox Code Playgroud)
这段代码给了我以下错误:
Explicit construction of entity type 'LINQPad.User.Product' in query is not allowed
Run Code Online (Sandbox Code Playgroud)
有没有一种简单的方法可以说“返回产品并可选择替换某些属性值”?
您有 3 个选择:
获取它们后处理它们 - 即
var products = ( /* first query */ ).ToList();
foreach(var item in products) {
item.Cost = ...;
item.Price = ...;
}
// and probably submit changes
Run Code Online (Sandbox Code Playgroud)创建一个不相关的类型(在模型之外)进行投影;甚至是匿名类型:
var products = /* most of second query */
select new { // <==== not a Product
ID = p.ID,
Description = p.Description,
....
Cost = pd.Cost.HasValue ? pd.Cost : p.Cost,
Price = pd.Price.HasValue ? pd.Price : p.Price,
...
};
Run Code Online (Sandbox Code Playgroud)与上面的几乎相同,但是破坏了组合(通过AsEnumerable(),这意味着我们将恢复到 LINQ-to-Objects 以用于后续内容)并在数据上下文之外创建一个更改的版本
var products = from prod in (/* first query */).AsEnumerable()
select new Product {
ID = p.ID,
Description = p.Description,
....
Cost = pd.Cost.HasValue ? pd.Cost : p.Cost,
Price = pd.Price.HasValue ? pd.Price : p.Price,
...
};
Run Code Online (Sandbox Code Playgroud)编辑重新评论;另一个选项是迭代器块;迭代器块是流媒体设备;编译器使用了很多魔法来确保您的代码一次只处理一项(“收益回报”)——它在返回任何内容之前不会读取所有数据:
static IEnumerable<Product> SomeMethod(IEnumerable<Product> products) {
foreach(p in products) {
p.Foo = ...
p.Bar = ...
yield return p;
}
}
Run Code Online (Sandbox Code Playgroud)
现在通过该方法传递产品序列。