Linq to SQL, как это сделать ", где [столбец] в (список значений)"

У меня есть функция, где я получаю список идентификаторов, и мне нужно вернуть список, соответствующий описанию, связанному с идентификатором. Например:.

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
}

Итак, если бы я сам создавал sql для этого, я бы просто сделал что-то вроде следующего (где предложение in содержит все значения в аргументе codeIds):

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

В Linq to Sql я не могу найти эквивалент предложения "IN". Самое лучшее, что я нашел до сих пор (что не работает):

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

Проблема заключается в том, что я не могу динамически генерировать список "OR" для linq для sql, потому что они установлены во время компиляции.

Как выполнить условие where, которое проверяет столбец, находится в динамическом списке значений с использованием Linq to Sql?

Ответ 1

Использование

where list.Contains(item.Property)

Или в вашем случае:

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

Но вы также можете сделать это в виде точечной нотации:

var foo = channel.AsQueryable<CodeData>()
                 .Where(codeData => codeIDs.Contains(codeData.CodeId));

Ответ 2

Вы также можете использовать:

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;

Ответ 3

Я использовал метод в ответе Джона Скита, но мне пришло другое, используя Concat. Метод Concat выполнялся немного лучше в ограниченном тесте, но это хлопот, и я, вероятно, просто придерживаюсь Contains, или, может быть, я напишу вспомогательный метод, чтобы сделать это для меня. В любом случае, здесь другой вариант, если кому-то интересно:

Метод

// 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
    );
}

Тест производительности

Это не было отдаленно научным. Я предполагаю, что ваша структура базы данных и количество идентификаторов, включенных в список, окажут значительное влияние.

Я установил тест, где я провел 100 испытаний каждый из Concat и Contains, где каждое исследование включало выбор 25 строк, заданных рандомизированным списком первичных ключей. Я запускаю это примерно десяток раз, и чаще всего метод Concat выходит на 5 - 10% быстрее, хотя один раз метод Contains выиграл всего лишь smidgen.

Ответ 4

 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();