在查询中更改 Linq To Sql 实体的属性

Mac*_*ros 3 c# linq-to-sql

我有 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)

有没有一种简单的方法可以说“返回产品并可选择替换某些属性值”?

Mar*_*ell 5

您有 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)

现在通过该方法传递产品序列。