【问题标题】:How to write dynamic Linq to count matching numbers如何编写动态 Linq 来计算匹配的数字
【发布时间】:2014-09-05 21:44:25
【问题描述】:

我在数据库中有两个表。票和票号。我想编写 Linq 来计算与传递给此函数的数字相匹配的票的数量。由于我们不知道必须匹配多少个数字,因此 Linq 必须是动态的……据我所知。

public int CountPartialMatchingTicket(IList<int> numbers)
{
    // where's the code? =_=;
}

假设现在数据库中有 3 张门票,我想计算所有编号为 3 和 4 的门票。

(1) 1 2 3 4
(2) 1 3 4 6 7
(3) 1 2 3

在这种情况下,函数应该返回 2,因为票 (1) 和 (2) 具有匹配的数字。 在另一种情况下,如果要求匹配 1、2、3,那么我们应该再次返回 2。

这是数据库中这两个表的样子:

Ticket:
TicketId, Name, AddDateTime

TicketNumbers:
Id, TicketId, Number

我以前从未使用过 Dynamic Linq,所以以防万一这是我的 cs 文件顶部的内容。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using LottoGen.Models;
using System.Linq.Dynamic;

首先,我什至不知道如何为固定数量的数字编写 Linq 行。我想 SQL 应该是这样的:

SELECT        TicketId, COUNT(0) AS Expr1
FROM          TicketNumber
WHERE         (Number = 3) OR (Number = 4)
GROUP BY      TicketId

但这也不是我想要的。上面的查询会得到有 3 或 4 的门票 - 但我只想要有两个号码的门票。而且我想它必须以某种方式嵌套才能返回单个计数。如果我必须用我的想象力来完成这个功能,那将是这样的:

public int CountPartialMatchingTicket(IList<int> numbers)
{
    string query = "";
    foreach(int number in numbers) {
        query += "Number = " + number.ToString() + " AND ";
    }
    // I know.. there is a trailing AND.. lazy
    int count = DbContext.TicketNumbers.Where(query).Count();
    return count;
}

哦,等一下。那里没有动态Linq...上面看起来像我会在PHP中做的事情,而那个查询语句显然没有做任何有用的事情。我在做什么? :(

最后,我想向网页输出一个小表格,如下所示。

Ticket             Matching Tickets
-----------------------------------
3 4                               2

三位一体,救命!

【问题讨论】:

    标签: c# linq entity-framework asp.net-mvc-4 dynamic-linq


    【解决方案1】:
     public int CountPartialMatchingTicket(IList<int> numbers)
     {
         var arr = numbers.ToArray();
         int count = DbContext.Tickets
                 .Count(tk=>arr.All(n=> tk.TicketNumbers.Any(tn=>tn.Number== n));
         return count;
     }
    

    更新:“如果您不介意,我如何将此查询限制为仅在特定的 AddDateTime(全天)制作的票?”

    Count() 方法调用内部的部分是 WHERE 条件,所以只需扩展它:

        DateTime targetDate = ......;
        DateTime tooLate = targetDate.AddDay(1);
    
         int count = DbContext.Tickets
                 .Count(tk=>
                           targetDate < tk.AddDateTime &&  tk.AddDateTime < tooLate
                           &&  arr.All(n=> tk.TicketNumbers.Any(tn=>tn.Number== n));
    

    【讨论】:

    • 我认为这可以解决问题,尽管由于它,我现在在应用程序上遇到了一些奇怪的行为。等我明白这一点后,我将不得不回复你。
    • 标记为答案。谢谢!如果您不介意,我如何将此查询限制为仅在特定的 AddDateTime(全天)发出的票?
    【解决方案2】:

    这类似于 James Curran 的回答,但更简单一些,它应该会产生一个更简单的基于 WHERE IN 的查询:

    // count all tickets...
    return DbContext.Tickets.Count(
        // where any of their ticket numbers
        tk => tk.TicketNumbers.Any(
            // are contained in our list of numbers
            tn => numbers.Contains(tn.Number)))
    

    【讨论】:

    • 您确定 IList 可以处理数据库查询吗?我认为它必须是一个数组。
    • @JamesCurran:我很确定这取决于您使用的 EF 版本。在 6 中,我的测试表明它几乎可以使用我扔给它的任何 IEnumerable 来做到这一点。
    • 好的。我习惯了 Linq2Sql。但是,您还有另一个问题——Any 中的tn 将是 TicketNumber 对象。您需要获取tn.Number 属性进行比较。
    • 这对我来说真的很神秘。但是,您的 n 在哪里声明?
    • 感谢您的反馈,伙计们。我做了你建议的修复,詹姆斯,我把它分解并评论了这些片段。
    猜你喜欢
    • 1970-01-01
    • 2013-06-19
    • 1970-01-01
    • 2023-02-04
    • 1970-01-01
    • 1970-01-01
    • 2021-08-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多