简体   繁体   English

Linq-复杂查询-列表中的列表

[英]Linq - complex query - list in a list

I have this class: 我有这个课:

public class RecipeLine
{
    public List<string> PossibleNames { get; set; }

    public string Name { get; set; }

    public int Index { get; set; }
}

I have a list of multiple RecipeLine objects. 我有多个RecipeLine对象的列表。 For example, one of them looks like this: 例如,其中一个看起来像这样:

Name: apple
PossibleNames: {red delicious, yellow delicious, ... }
Index = 3

I also have a table in my db which is called tblFruit and has 2 columns: name and id. 我的数据库中还有一个名为tblFruit的表,该表有2列:名称和ID。 the id isn't the same as the index in the class. id与类中的索引不同。

What I want to do is this: for the whole list of RecipeLine objects, find all the records in tblFruit whose name is in PossibleNames, and give me back the index of the class and the id in the table. 我想做的是:对于RecipeLine对象的整个列表,在tblFruit中找到所有记录,这些记录的名称在“ PropertyNames”中,然后将类的索引和ID返回表中。 So we have a list in a list (a list of RecipeLine objects who have a list of strings). 因此,我们在列表中有一个列表(具有字符串列表的RecipeLine对象的列表)。 How can I do this with Linq in c#? 如何在C#中使用Linq做到这一点?

I'm pretty sure there isn't going to be a LINQ statement that you can construct for this that will create a SQL query to get the data exactly how you want. 我很确定不会有为此可以构造的LINQ语句,该语句将创建一个SQL查询以获取所需数据。 Assuming tblFruit doesn't have too much data, pull down the whole table and process it in memory with something like... 假设tblFruit没有太多的数据,拉下整个表并且用类似处理它在内存中...

var result = tblFruitList.Select((f) => new {Id = f.id, Index = recipeLineList.Where((r) => r.PossibleNames.Contains(f.name)).Select((r) => r.Index).FirstOrDefault()});

Keeping in mind that Index will be 0 if there isn't a recipeLine with the tblFruit's name in it's PossibleNames list. 请记住,如果在“可能的名称”列表中没有带有tblFruit名称的配方线,则索引将为0。

A more readable method that doesn't one-line it into a nasty linq statement is... 不会将其单行放入讨厌的linq语句中的更具可读性的方法是...

Class ResultItem {
    int Index {get;set;}
    int Id {get;set;}
}

IEnumerable<ResultItem> GetRecipeFruitList(IEnumerable<FruitItem> tblFruitList, IEnumerable<RecipeLine> recipeLineList) {
    var result = new List<ResultItem>();
    foreach (FruitItem fruitItem in tblFruitList) {
        var match = recipeLineList.FirstOrDefault((r) => r.PossibleNames.Contains(fruitItem.Name));
        if (match != null) {
            result.Add(new ResultItem() {Index = match.Index, Id = fruitItem.Id});
        }
    }
    return result;
}

If tblFruit has a lot of data you can try and pull down only those items that have a name in the RecipeLine list's of PossibleName lists with something like... 如果tblFruit包含大量数据,则可以尝试仅将那些在RecipeLine列表中可能名称列表中具有名称的项目下拉,例如...

var allNames = recipeLineList.SelectMany((r) => r.PossibleNames).Distinct();
var tblFruitList = DbContext.tblFruit.Where((f) => allNames.Contains(f.Name));

要获取表中Name在“ PossibleNames Name所有水果,请使用以下命令:

var query = myData.Where(x => myRecipeLines.SelectMany(y => y.PossibleNames).Contains(x.Name));

I don't think you can do this in a single step. 我认为您不能一步一步做到这一点。

I would first create a map of the possible names to indexes: 我首先创建一个可能的名称到索引的映射:

var possibleNameToIndexMap = recipes
    .SelectMany(r =>  r.PossibleNames.Select(possibleName => new { Index = r.Index, PossbileName = possibleName }))
    .ToDictionary(x => x.PossbileName, x => x.Index);

Then, I would retrieve the matching names from the table: 然后,我将从表中检索匹配的名称:

var matchingNamesFromTable = TblFruits
    .Where(fruit => possibleNameToIndexMap.Keys.Contains(fruit.Name))
    .Select(fruit => fruit.Name);

Then you can use the names retrieved from the tables as keys into your original map: 然后,您可以使用从表中检索到的名称作为原始地图的键:

var result = matchingNamesFromTable
    .Select(name => new { Name = name, Index = possibleNameToIndexMap[name]});

Not fancy, but it should be easy to read and maintain. 不花哨,但应该易于阅读和维护。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM