【问题标题】:access an array element inside a LINQ to Entities set访问 LINQ to Entities 集中的数组元素
【发布时间】:2017-04-21 01:09:45
【问题描述】:

我在 Linq 查询中对字符串使用 Split 方法,但只需要第二个元素。我在下面的代码中得到“System.InvalidOperationException: 'Unrecognized expression node: ArrayIndex'”:

    var RMA_stops_all = (from rma in rDb.DistributionStopInformations
                         join line in rDb.DistributionLineItems on rma.UniqueIdNo equals line.UniqueIdNo
                         where line.RmaNumber != null 
                         &&
                         (line.DatetimeCreated > Convert.ToDateTime(dateToCheck_rma) &&
                         line.DatetimeCreated < Convert.ToDateTime(dateToCheck_rma).AddDays(7))
                         && rma.CustomerNo == TNGCustNo
                         select new
                         {
                             dtCreated = line.DatetimeCreated,
                             UniqueIdNo = rma.UniqueIdNo,
                             RmaNumber = line.RmaNumber,
                             RmaOriginalUniqueId = line.RmaOriginalUniqueId,
                             ItemSequenceNo = line.ItemSequenceNo,
                             ItemNumber = line.ItemNumber,
                             goodRMA_flag =  line.RmaNumber.Contains("/078"),
                             rmaGood = line.RmaNumber.Split(new string[] { "/" }, StringSplitOptions.None)[1]
                         }).ToArray();

如果我删除数组上的 [1] 它可以工作,我可以通过以下方式访问整个数据集的两个元素:

  foreach (var item in RMA_stops_all)
        {
         var right = RMA_stops_all.First().rmaGood[1];
         var left = RMA_stops_all.First().rmaGood[0];
            Console.WriteLine("left {0} - right{1} ",left.ToString(), right.ToString());
        }

编辑 - 呃。上面的“测试”完全没有用(正如温和地指出的那样) - 但是,下面确实证明它工作正常(一些返回的值只有 1 个元素,因此额外的 if 块 - 输出符合预期:

 foreach (var item in RMA_stops_all)
            {
                string right, left;
                if (item.rmaGood.Length == 1)
                {
                     left = item.rmaGood[0].ToString();
                     right = "Not there";
                }
                else
                {
                 left = item.rmaGood[0].ToString();
                 right = item.rmaGood[1].ToString();
                }
                Console.WriteLine("left {0} - right{1} ", left, right);
            }

来自 dbMonitor 的 SQL 输出:

SELECT t2.datetime_created AS "DatetimeCreated", 
       t1.unique_id_no AS "UniqueIdNo", 
       t2.rma_number AS "RmaNumber", 
       t2.rma_original_unique_id AS "RmaOriginalUniqueId",
       t2.item_sequence_no AS "ItemSequenceNo", 
       t2.item_number AS "ItemNumber", 
       (t2.rma_number LIKE :p3) OR (t2.rma_number LIKE :p4) AS "C1",
       t2.rma_number AS "RmaNumber1"
FROM cops_reporting.distribution_stop_information t1
INNER JOIN cops_reporting.distribution_line_items t2 
    ON t1.unique_id_no = t2.unique_id_no
WHERE (t2.rma_number IS NOT NULL) 
   AND (t2.datetime_created > :p0)
   AND (t2.datetime_created < :p1)
   AND (t1.customer_no = :p2)

【问题讨论】:

  • EF 支持String.Split? SQL 查询长什么样子?
  • 好像没有字符串拆分
  • 但它运行并返回一个我可以访问的数组?
  • 我在 SQL 中也没有看到它,LINQ 是否正在执行它来发布结果?
  • 我正在使用 DevArt 的 postgresql 数据连接器——这会有什么不同吗?

标签: c# linq


【解决方案1】:

我没有意识到 Linq to Entities 可以直接访问某些 SQL 函数,所以这可能对您有用:

var RMA_stops_all = (from rma in rDb.DistributionStopInformations
                     join line in rDb.DistributionLineItems on rma.UniqueIdNo equals line.UniqueIdNo
                     where line.RmaNumber != null 
                     &&
                     (line.DatetimeCreated > Convert.ToDateTime(dateToCheck_rma) &&
                     line.DatetimeCreated < Convert.ToDateTime(dateToCheck_rma).AddDays(7))
                     && rma.CustomerNo == TNGCustNo
                     select new
                     {
                         dtCreated = line.DatetimeCreated,
                         UniqueIdNo = rma.UniqueIdNo,
                         RmaNumber = line.RmaNumber,
                         RmaOriginalUniqueId = line.RmaOriginalUniqueId,
                         ItemSequenceNo = line.ItemSequenceNo,
                         ItemNumber = line.ItemNumber,
                         goodRMA_flag =  line.RmaNumber.Contains("/078"),
                         rmaGood = line.RmaNumber.Substring(line.RmaNumber.IndexOf("/")+1)
                     }).ToArray();

假设 RmaNumber 看起来像 #/# 并且没有要避免的额外斜线。

【讨论】:

  • Substring vs Substr - SO 不接受 3 个字符的编辑,所以我不能只是改变它。否则 - 是的,以上确实有效。然而,它并没有解决如何(或不可能)访问由拆分函数生成的元素的原始问题。然而,对实际问题的很好的解决方案和 IndexOf 的巧妙使用——我忘记了!
  • 谢谢 - 修正了错字。我脑子里的语言太多了!使用 MS SQL 进行测试,似乎不管文档在某些时候 MS 在 Linq to SQL/EF 中实现了 String.Split(),显然是在客户端处理的,但不是数组索引或其他使用数组的处理(例如 Last()) .
  • 另外,显然只在最终选择中(例如,尝试选择多个拆分会导致 SQL 错误中未实现)。
【解决方案2】:

我不明白为什么它在没有索引操作的情况下也能工作,而且您的 SQL 似乎没有反映相同的 Linq 代码(您使用过 LinqPad 吗?),但我建议您这样做,因为您正在执行 .ToArray( ) 无论如何,将拆分/索引移动到客户端:

var RMA_stops_all = (from rma in rDb.DistributionStopInformations
                     join line in rDb.DistributionLineItems on rma.UniqueIdNo equals line.UniqueIdNo
                     where line.RmaNumber != null 
                     &&
                     (line.DatetimeCreated > Convert.ToDateTime(dateToCheck_rma) &&
                     line.DatetimeCreated < Convert.ToDateTime(dateToCheck_rma).AddDays(7))
                     && rma.CustomerNo == TNGCustNo
                     select new
                     {
                         dtCreated = line.DatetimeCreated,
                         rma.UniqueIdNo,
                         line.RmaNumber,
                         line.RmaOriginalUniqueId,
                         line.ItemSequenceNo,
                         line.ItemNumber,
                         goodRMA_flag =  line.RmaNumber.Contains("/078"),
                     }).AsEnumerable().Select(r => new {
                         r.dtCreated,
                         r.UniqueIdNo,
                         r.RmaNumber,
                         r.RmaOriginalUniqueId,
                         r.ItemSequenceNo,
                         r.ItemNumber,
                         r.goodRMA_flag,
                         rmaGood = r.RmaNumber.Split(new string[] { "/" }, StringSplitOptions.None)[1]
                     });

顺便说一句,您不必为简单的访问器表达式重复字段/属性名称,因此我将它们从您的原始选择中删除。此外,如果您可以使用双重间接,则可以在第二个选择中包含 r。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-09
    • 1970-01-01
    • 2020-09-23
    • 1970-01-01
    • 1970-01-01
    • 2012-01-02
    • 2010-11-02
    • 1970-01-01
    相关资源
    最近更新 更多