Как динамически добавлять оператор OR в предложение WHERE в LINQ
У меня есть массив строк с переменным размером, и я пытаюсь запрограммировать цикл через массив и сопоставлять все строки в таблице, где столбец «Метки» содержит хотя бы одну из строк в массиве. Вот несколько псевдокодов:
IQueryable allSongMatches = musicDb.Songs; // all rows in the table
Я могу легко запросить эту фильтрацию таблицы на фиксированном наборе строк, например:
allSongMatches=allSongMatches.Where(SongsVar => SongsVar.Tags.Contains("foo1") || SongsVar.Tags.Contains("foo2") || SongsVar.Tags.Contains("foo3"));
Однако это не работает (я получаю следующую ошибку: «Лямбда-выражение с телом оператора не может быть преобразовано в дерево выражений»)
- Полиморфизм. Является ли объект ORM субъектом домена или объектом данных?
- Я не понимаю LINQ to SQL .AsEnumerable ()?
- Как удалить функциональность подразделения из репозиториев с помощью IOC
- Считаете ли вы целесообразным перейти на Entity Framework?
- Есть ли шаблон, использующий Linq для динамического создания фильтра?
allSongMatches = allSongMatches.Where(SongsVar => { bool retVal = false; foreach(string str in strArray) { retVal = retVal || SongsVar.Tags.Contains(str); } return retVal; });
Может ли кто-нибудь показать мне правильную страtagsю для этого? Я все еще новичок в мире LINQ 🙂
- Что я могу сделать, чтобы разрешить исключение «Row not found or changed» в LINQ to SQL в базе данных SQL Server Compact Edition?
- Условные запросы Linq
- LINQ Между оператором
- Поддерживает ли AutoMapper Linq?
- Linq «Не удалось перевести выражение ... в SQL и не смог обработать его как локальное выражение».
- Случайная строка от Linq до Sql
- Как получить строку MAX с запросом GROUP BY в LINQ?
- Entity Framework vs LINQ to SQL
Вы можете использовать class PredicateBuilder
:
var searchPredicate = PredicateBuilder.False(); foreach(string str in strArray) { var closureVariable = str; // See the link below for the reason searchPredicate = searchPredicate.Or(SongsVar => SongsVar.Tags.Contains(closureVariable)); } var allSongMatches = db.Songs.Where(searchPredicate);
LinqToSql странное поведение
Недавно я создал метод расширения для создания поиска строк, который также позволяет выполнять поиск OR
. О блоге
Я также создал его как пакет nuget, который вы можете установить:
http://www.nuget.org/packages/NinjaNye.SearchExtensions/
После установки вы сможете сделать следующее
var result = db.Songs.Search(s => s.Tags, strArray);
Если вы хотите создать свою собственную версию, чтобы разрешить вышеуказанное, вам нужно будет сделать следующее:
public static class QueryableExtensions { public static IQueryable Search (this IQueryable source, Expression> stringProperty, params string[] searchTerms) { if (!searchTerms.Any()) { return source; } Expression orExpression = null; foreach (var searchTerm in searchTerms) { //Create expression to represent x.[property].Contains(searchTerm) var searchTermExpression = Expression.Constant(searchTerm); var containsExpression = BuildContainsExpression(stringProperty, searchTermExpression); orExpression = BuildOrExpression(orExpression, containsExpression); } var completeExpression = Expression.Lambda>(orExpression, stringProperty.Parameters); return source.Where(completeExpression); } private static Expression BuildOrExpression(Expression existingExpression, Expression expressionToAdd) { if (existingExpression == null) { return expressionToAdd; } //Build 'OR' expression for each property return Expression.OrElse(existingExpression, expressionToAdd); } }
Кроме того, взгляните на проект github для NinjaNye.SearchExtensions
как у этого есть другие варианты, и он был частично реорганизован, чтобы разрешить другие комбинации
Либо создайте Expression
самостоятельно, либо посмотрите на другой маршрут.
Предполагая, что possibleTags представляет собой набор тегов, вы можете использовать закрытие и соединение, чтобы найти совпадения. Это должно найти любые песни с хотя бы одним тегом в возможныхTags:
allSongMatches = allSongMatches.Where(s => (select t from s.Tags join tt from possibleTags on t == tt select t).Count() > 0)
Есть другой, несколько более простой метод, который это выполнит. Блог ScottGu описывает динамическую библиотеку linq, которую я нашел очень полезной в прошлом. По существу, он генерирует запрос из строки, в которую вы проходите. Вот пример кода, который вы должны написать:
Dim Northwind As New NorthwindDataContext Dim query = Northwind.Products _ .Where("CategoryID=2 AND UnitPrice>3") _ .OrderBy("SupplierId") Gridview1.DataSource = query Gridview1.DataBind()
Более подробную информацию можно найти в блоге scottgu .