【问题标题】:SQL to LINQ with Case .. When in Order BySQL to LINQ with Case .. 何时按顺序排列
【发布时间】:2016-01-22 02:37:11
【问题描述】:

我有一个想要转换为 LINQ 查询的 SQL 查询,但我不知道如何继续。我有两个实体ProductPricePrice 通过ProductId 链接到Product。该查询根据请求的Product 的数量获取产品的最优价格。

例如:如果客户想要购买 10 件产品,则该产品的价格可能为 5 美元/件。但是,如果客户想要购买 100 件产品,那么成本可能是 3 美元/件。此查询将根据请求的数量获得最佳单价。 WHERE 子句确保选择了正确的产品,如果日期已过,则不包括任何价格。 CASE 语句对价格进行排序,只要达到请求的数量,就会首先显示最优惠的价格。

Price Table
--------------------------
Id    ProductId      Quantity     Price    BeginDate   EndDate
=========================================================================
1     1234           10           $5       1/1/2016    2/1/2016
2     1234           100          $3       1/1/2016    2/1/2016
3     1234           100          $1       1/1/2016    1/9/2016
4     1234           500          $2       1/1/2016    2/1/2016



SELECT TOP 1
  Product.Id,
  Product.Name,
  Prices.Price
FROM Products INNER JOIN Prices ON Products.Id = Prices.ProductId
WHERE Product.Id = @ProductId
  AND ((Price.BeginDate IS NULL OR Price.BeginDate < GETDATE()) AND (Price.EndDate IS NULL OR Price.EndDate > GETDATE())) 
ORDER BY
  CASE WHEN Price.Quantity <= @RequestedQuantity THEN Price.Quantity 
   ELSE -Price.Quantity
  END

在 LINQ 中让我感到困惑的查询部分 ..

  1. 如何过滤出价格日期已过期的价格(例如 Id = 3)。
  2. 如何使用 case 语句对集合进行排序。

一旦这些都到位,我就可以使用FirstOrDefault 选择最佳结果

【问题讨论】:

  • 你在使用实体框架吗?我忘了问。
  • 这可能是一个愚蠢的问题,但是...通过将查询转换为 LINQ 可以得到什么?从查询 SQL 数据源的情况来看,它已经在 SQL 中工作了。将它放入 LINQ 会迫使您执行当前卡住的翻译,并让系统重新计算您已有的 SQL。
  • @eftpotrm - 这根本不是一个愚蠢的问题。你是对的,我确实把它作为一个存储过程工作,我可以从实体框架中执行它。事实上,我认为使用存储过程是获取正确记录的最佳方式。如果需要,我对如何通过 LINQ 编写查询感到困惑。
  • @Blue Eyed Behemoth - 对不起,我应该提到这一点。是的,我正在使用实体框架 v6。
  • @webworm 我更新了我的答案,现在应该更有意义(如果您不在.Net 4.6 上,请检查null 而不是使用?)。另外,我了解您的结构,哈哈

标签: c# linq


【解决方案1】:

尝试使用let 关键字来定义列并对其进行排序。我没有测试它,我不确定它会按你的预期工作。确保您已在其上定义了所有实体和属性,例如:

var query = from product in Products 
            join price in Prices on product.Id equals price.ProductId
            let priceOrder = price.Quantity <= requestValue ? price.Quantity : -price.Quantity 
            where ((price.BeginDate == null || Price.BeginDate < DateTime.Now) && (Price.EndDate == null || Price.EndDate > DateTime.Now))
            orderby priceOrder 
            select { product.Id, product.Name, price.Price };

var result = query.FirstOrDefault();

【讨论】:

    【解决方案2】:

    如果您使用的是实体框架

    SELECT TOP 1
      Product.Id,
      Product.Name,
      Prices.Price
    FROM Products INNER JOIN Prices ON Products.Id = Prices.ProductId
    WHERE Product.Id = @ProductId
      AND ((Price.BeginDate IS NULL OR Price.BeginDate < GETDATE()) AND (Price.EndDate IS NULL OR Price.EndDate > GETDATE())) 
    ORDER BY
      CASE WHEN Price.Quantity <= @RequestedQuantity THEN Price.Quantity 
       ELSE -Price.Quantity
      END
    

    应该看起来像

    var SelectedProduct = ObjectYourDatabaseIsLabeledAs.Products
        .FirstOrDefault(p => p.Id == ProductId) // Gets matching Ids
    

    或者

    var SelectedProduct = ObjectYourDatabaseIsLabeledAs.Products.Find(ProductId)
    

    然后得到合适的价格

    var SelectedPrice = SelectedProduct?.Prices
        .OrderByDesc(o => o.Quantity) // Sets the highest number at the top of the IEnum
        .FirstOrDefault(p => // Take the first/default one where...
            p.EndDate >= DateTime.Today &&
            p.StartDate <= DateTime.Today && // Gets All With Valid Prices
            p.Quantity <= RequestedQuantity) // Removes all the high quantities that you don't want
    

    【讨论】:

    • 抱歉更新我的答案 10 次,我只是一直意识到我忘记了一些东西哈哈
    【解决方案3】:

    几乎是一对一的翻译。

    SQL

    SELECT TOP 1 Product.Id, Product.Name, Prices.Price
    FROM Products
    INNER JOIN Prices ON Products.Id = Prices.ProductId
    WHERE Product.Id = @ProductId
        AND (Price.BeginDate IS NULL OR Price.BeginDate < GETDATE())
        AND (Price.EndDate IS NULL OR Price.EndDate > GETDATE()) 
    ORDER BY CASE WHEN Price.Quantity <= @RequestedQuantity THEN Price.Quantity ELSE -Price.Quantity END
    

    LINQ

    var productId = ...;
    var requestedQuantity = ...;
    var date = DateTime.Today;
    
    var query = 
        (from product in db.Products
         join price in db.Prices on product.Id equals price.ProductId
         where product.Id == productId
             && (price.BeginDate == null || price.BeginDate < date)
             && (price.EndDate == null || price.EndDate > date)
         orderby price.Quantity <= requestedQuantity ? price.Quantity : -price.Quantity
         select new { product.Id, product.Name, price.Price }
        ).Take(1);
    
    var result = query.FirstOrDefault();
    

    唯一的区别是 select 排在最后,CASE WHEN condition THEN a ELSE b END 映射到 condition ? a : bTOP n 变成 .Take(n)

    实际上这里不需要Take(1),我把它包括在内只是为了比较,以防你需要TOP 10

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多