【问题标题】:Change property of Linq To Sql Entity in query在查询中更改 Linq To Sql 实体的属性
【发布时间】:2010-12-12 17:13:47
【问题描述】:

我有 2 个表 Products 和 ProductDetails。 Products 包含有关我的库存的所有信息,ProductDetails 用于允许在产品价格更改生效之前在系统中更新它们。

我正在尝试编写一个简单的查询,该查询返回所有产品,并且如果在 ProductDetails 中找到匹配行且 CommenceDate 小于或等于当前日期,还会更新产品的成本和价格。到目前为止我所拥有的是:

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;

我首先认为我可以通过在选择中声明一个新产品来实现我所追求的目标,例如:

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,
                    ...
               };

这段代码给了我以下错误:

Explicit construction of entity type 'LINQPad.User.Product' in query is not allowed

是否有一种简单的方式来表示“退回产品并可选择替换某些属性值”?

【问题讨论】:

    标签: c# linq-to-sql


    【解决方案1】:

    您有 3 个选项:

    • 在获取它们之后处理项目 - 即

      var products = ( /* first query */ ).ToList();
      foreach(var item in products) {
          item.Cost = ...;
          item.Price = ...;
      }
      // and probably submit changes
      
    • 创建一个不相关的类型(在模型之外)进行投影;甚至是匿名类型:

      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,
                          ...
                     };
      
    • 与上面几乎相同,但破坏了组合(通过AsEnumerable(),这意味着我们在接下来的任何内容中都恢复到 LINQ-to-Objects)并创建了一个更改版本 outside数据上下文

      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,
                          ...
                     };
      

    编辑re cmets;另一种选择是迭代器块;迭代器块是 流媒体 设备;编译器编织了很多魔法来确保您的代码一次只处理一个项目(“yield return”) - 它在返回任何内容之前不会读取所有数据:

    static IEnumerable<Product> SomeMethod(IEnumerable<Product> products) {
        foreach(p in products) {
            p.Foo = ...
            p.Bar = ...
            yield return p;
        }
    }
    

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

    【讨论】:

    • 这是我希望避免的——我在数据库中有很多产品,所以循环遍历不是一种选择。在Sql中会很容易! (或者如果我可以在查询中实例化一个实体,则在 Linq To Sql 中)
    • @Macros,您可以随时将 TSQL 与 ExecuteQuery&lt;T&gt; 一起使用。
    • @macros 实际上它可以写在一个迭代器块中,所以它是惰性的/每个项目;那么您不会有任何初始的额外延迟 - 这会有帮助吗?
    • @Marc - 看起来这将是最好的选择。我一直在尝试避免使用 Sql,因为我对 Linq 还很陌生,感觉就像是在作弊,而不是找到正确的“Linq-to-sql”做事方式,但我猜这只是知道何时使用每种方法的情况。
    • @Marc,我还将在网格中显示产品,因此即使它们是延迟加载,它仍然会比基于集合的方法慢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多