110

I have a function where I get a list of ids, and I need to return the a list matching a description that is associated with the id. E.g.:

public class CodeData
{
    string CodeId {get; set;}
    string Description {get; set;}
}

public List<CodeData> GetCodeDescriptionList(List<string> codeIDs)
    //Given the list of institution codes, return a list of CodeData
    //having the given CodeIds
}

So if I were creating the sql for this myself, I would simply do something like the following (where the in clause contains all the values in the codeIds argument):

Select CodeId, Description FROM CodeTable WHERE CodeId IN ('1a','2b','3')

In Linq to Sql I can't seem to find the equivalent of the "IN" clause. The best I've found so far (which doesn't work) is:

 var foo = from codeData in channel.AsQueryable<CodeData>()
           where codeData.CodeId == "1" || codeData.CodeId == "2"
           select codeData;

The problem being, that I can't dynamically generate a list of "OR" clauses for linq to sql, because they are set at compile time.

How does one accomplish a where clause that checks a column is in a dynamic list of values using Linq to Sql?

Nathan
  • 10,593
  • 10
  • 63
  • 87

6 Answers6

175

Use

where list.Contains(item.Property)

Or in your case:

var foo = from codeData in channel.AsQueryable<CodeData>()
          where codeIDs.Contains(codeData.CodeId)
          select codeData;

But you might as well do that in dot notation:

var foo = channel.AsQueryable<CodeData>()
                 .Where(codeData => codeIDs.Contains(codeData.CodeId));
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    how to use in case of CodeId is Integer?? – Kiran Solkar Dec 03 '16 at 08:53
  • 3
    @KiranSolkar: Then presumably `codeIDs` would be a `List`, and all would be fine. – Jon Skeet Dec 03 '16 at 08:59
  • @JonSkeet Isn't that case sensitive? If codeIDs is list of uppercase strings and codeData.codeId is a lowercase string, it'll fail. – PersyJack May 31 '17 at 20:03
  • @PersyJack: There was nothing in the question about it having to be case-insensitive. As for whether or not it would be, I can't remember whether LINQ to SQL enforces case-sensitivity by default or lets the db settings govern it. – Jon Skeet May 31 '17 at 20:36
  • 1
    @PersyJack LINQ to SQL generates the T-SQL query, which then runs on the SQL Server using the database settings for case-sensitivity. Although, if one is not careful, and materializes the query results, before applying LINQ to in-memory objects, they may suffer the consequences of mismatched case-sensitivity. – Zarepheth Sep 26 '18 at 21:06
  • @JonSkeet Dot notation... meh. I appreciate it's source in extension methods, which I love, but I've seen this stuff run out to multiple nested lengths that are just ridiculous and make code completely unreadable. The more time goes by, the less of a virtue I think it is. Just one man's opinion. – Craig Tullis Oct 18 '22 at 03:35
  • @CraigTullis: Whereas I've found that I've continued to use LINQ heavily, but I hardly *ever* use query expressions. Each to their own. – Jon Skeet Oct 18 '22 at 03:42
29

You could also use:

List<int> codes = new List<int>();

codes.add(1);
codes.add(2);

var foo = from codeData in channel.AsQueryable<CodeData>()
          where codes.Any(code => codeData.CodeID.Equals(code))
          select codeData;
Nick DeMayo
  • 1,086
  • 2
  • 15
  • 23
1

I had been using the method in Jon Skeet's answer, but another one occurred to me using Concat. The Concat method performed slightly better in a limited test, but it's a hassle and I'll probably just stick with Contains, or maybe I'll write a helper method to do this for me. Either way, here's another option if anyone is interested:

The Method

// Given an array of id's
var ids = new Guid[] { ... };

// and a DataContext
var dc = new MyDataContext();

// start the queryable
var query = (
    from thing in dc.Things
    where thing.Id == ids[ 0 ]
    select thing 
);

// then, for each other id
for( var i = 1; i < ids.Count(); i++ ) {
    // select that thing and concat to queryable
    query.Concat(
        from thing in dc.Things
        where thing.Id == ids[ i ]
        select thing
    );
}

Performance Test

This was not remotely scientific. I imagine your database structure and the number of IDs involved in the list would have a significant impact.

I set up a test where I did 100 trials each of Concat and Contains where each trial involved selecting 25 rows specified by a randomized list of primary keys. I've run this about a dozen times, and most times the Concat method comes out 5 - 10% faster, although one time the Contains method won by just a smidgen.

DCShannon
  • 2,470
  • 4
  • 19
  • 32
0
 var filterTransNos = (from so in db.SalesOrderDetails
                    where  ItemDescription.Contains(ItemDescription)
                            select new { so.TransNo }).AsEnumerable();    


listreceipt = listreceipt.Where(p => filterTransNos.Any(p2 => p2.TransNo == p.TransNo)).ToList();
Deepan Raj
  • 194
  • 3
  • 11
0

Here is how I do it by using HashSet

        HashSet<String> hs = new HashSet<string>(new String[] { "Pluto", "Earth", "Neptune" });
        String[] arr =
        {
            "Pluto",
            "Earth",
            "Neptune",
            "Jupiter",
            "Saturn",
            "Mercury",
            "Pluto",
            "Earth",
            "Neptune",
            "Jupiter",
            "Saturn",
            "Mercury",
            // etc.
        };
        ICollection<String> coll = arr;

        String[] arrStrFiltered = coll.Where(str => hs.Contains(str)).ToArray();

HashSet is basically almost to O(1) so your complexity remains O(n).

M G
  • 47
  • 1
  • This is about LINQ-to-SQL. Such LINQ-to-objects considerations don't apply. – Gert Arnold Nov 03 '19 at 16:29
  • 1
    ICollection can come from a LINQ-SQL too, this is a generic way – M G Nov 17 '19 at 08:24
  • 1
    The question is about how to build an expression that translates into correct SQL. That has nothing to do with how to search a local collection. Your answer will only delude future readers that aren't aware of this distinction. – Gert Arnold Nov 17 '19 at 09:49
0

No Entity Framework Net Core 2

string[] names = stringsTest.name.Split('|');

if (names.Length > 1)
{
    query = query.Where(w => names.Contains(w.name));
}
else
{
    query = query.Where(w => w.name== stringsTest.name);
}

var listEntity = await query.ToListDtoAsync(stringsTest);