如何在EF中获取与组合(键/值)列表匹配的记录?

时间:2020-01-03 15:27:24

标签: c# entity-framework linq

我有一个数据库表,其中包含每个用户/年份组合的记录。

如何使用EF和userId / year组合列表从数据库中获取数据? 样本组合

UserId      Year
1           2015
1           2016 
1           2018
12          2016
12          2019
3           2015
91          1999

我只需要以上组合中定义的记录。不能用EF / Linq编写代码吗?

 List<UserYearCombination> userYears =  GetApprovedYears();

 var records = dbcontext.YearResults.Where(?????);

课程

public class YearResult
{
    public int UserId;
    public int Year;
    public DateTime CreatedOn;
    public int StatusId;
    public double Production;
    public double Area;
    public double Fte;
    public double Revenue;
    public double Diesel;
    public double EmissionsCo2;
    public double EmissionInTonsN;
    public double EmissionInTonsP;
    public double EmissionInTonsA;
        ....
}

public class UserYearCombination
{
    public int UserId;
    public int Year;
}

2 个答案:

答案 0 :(得分:2)

这是我在here之前讨论的一个臭名昭著的问题。克里希纳·穆帕拉(Krishna Muppalla)的解决方案是我在那里提出的解决方案之一。它的缺点是它不可靠,即不能从涉及的数据库字段上的任何索引中受益。

同时,我提出了另一种在某些情况下可能有用的解决方案。基本上,它按字段之一对输入数据进行分组,然后按分组键和包含组元素的包含查询查找并合并数据库数据:

IQueryable<YearResult> items = null;

foreach (var yearUserIds in userYears.GroupBy(t => t.Year, t => t.UserId))
{
    var userIds = yearUserIds.ToList();
    var grp = dbcontext.YearResults
        .Where(x => x.Year == yearUserIds.Key 
                 && userIds.Contains(x.UserId));
    items = items == null ? grp : items.Concat(grp);
}

我在这里使用Concat是因为Union会浪费时间,使结果变得不同,并且在EF6中,Concat会生成带有链接的UNION语句的SQL,而Union会生成嵌套的UNION条语句和最大嵌套级别可能会被击中。

在建立索引后,此查询的性能可能会很好。从理论上讲,SQL语句中UNION的最大数量是不受限制的,但是IN子句(Contains转换为)中的项目数不应超过几千。那意味着 数据的内容将确定哪个分组字段表现更好,YearUserId。面临的挑战是使UNION的数量最小化,同时使所有IN子句中的项目数保持低于大约。 5000。

答案 1 :(得分:1)

您可以尝试

//add the possible filters to LIST
var searchIds = new List<string> { "1-2015", "1-2016", "2-2018" };

//use the list to check in Where clause
var result = (from x in YearResults
        where searchIds.Contains(x.UserId.ToString()+'-'+x.Year.ToString())
        select new UserYearCombination
        {
            UserId = x.UserId,
            Year = x.Year
        }).ToList();

方法2

var d = YearResults
           .Where(x=>searchIds.Contains(x.UserId.ToString() + '-' + x.Year.ToString()))
           .Select(x => new UserYearCombination
                 {
                      UserId = x.UserId,
                      Year = x.Year
                 }).ToList();