Есть ли способ создать предложение not in, как это было бы в SQL Server в Linq для сущностей?





Пытаться:
from p in db.Products
where !theBadCategories.Contains(p.Category)
select p;
Какой SQL-запрос вы хотите преобразовать в Linq-запрос?
Если вы используете коллекцию в памяти в качестве фильтра, вероятно, лучше всего использовать отрицание Contains (). Обратите внимание, что это может не сработать, если список слишком длинный, и в этом случае вам нужно будет выбрать другую стратегию (см. Ниже для использования стратегии для полностью ориентированного на БД запроса).
var exceptionList = new List<string> { "exception1", "exception2" };
var query = myEntities.MyEntity
.Select(e => e.Name)
.Where(e => !exceptionList.Contains(e.Name));
Если вы исключаете на основе другого запроса к базе данных, лучше использовать Except. (Вот ссылка на сайт для поддерживаемых расширений Set в LINQ to Entities)
var exceptionList = myEntities.MyOtherEntity
.Select(e => e.Name);
var query = myEntities.MyEntity
.Select(e => e.Name)
.Except(exceptionList);
Это предполагает сложную сущность, в которой вы исключаете определенные в зависимости от некоторого свойства другой таблицы и хотите, чтобы имена сущностей не исключались. Если вам нужна вся сущность, тогда вам нужно будет создать исключения как экземпляры класса сущности, чтобы они удовлетворяли оператору равенства по умолчанию (см. документы).
@GertArnold, не могли бы вы уточнить выражение «производит ужасный SQL»? Я использую Except, и он работает нормально. Никаких странностей, ни причуд производительности, AFAIK.
@NinjaCross Оператор, как в ответе выше, производит SQL с n-1 предложениями UNION ALL, где n - количество элементов в exceptionList. Я просто пробовал с EF 6.1, так что дело не в том, что он улучшился или что-то в этом роде. В EF 4.1 то же самое, поэтому я просто не понимаю, почему этот ответ вообще был принят. Предлагающий Contains ответ правильный. Я думаю, вы использовали Except с другим IQueryable, поэтому EF смог преобразовать его в SQL EXCEPT. А ты?
@GertArnold - not Contains вполне допустимо в пределах ограничения, согласно которому предложение NOT IN ограничивается примерно 2000 записями. После этого вы можете получить ошибку ресурсов SQL. Вероятно, это то, что я бы использовал в простом случае.
@GertArnold, вот что я делаю: (из e в dataModel.TABLE1 выберите e.ID) .Except (dataModel.TABLE2.Select (m => m.LightTypeID)). Min (); Это сгенерированный запрос: SELECT [GroupBy1]. [A1] AS [C1] FROM (SELECT MIN ([Except1]. [ID]) AS [A1] FROM (SELECT [Extent1]. [ID] AS [ID] FROM [dbo]. [TABLE1] AS [Extent1] EXCEPT SELECT [Extent2]. [LightTypeID] AS [LightTypeID] FROM [dbo]. [TABLE2] AS [Extent2]) AS [Except1]) AS [GroupBy1]
@NinjaCross Действительно, это два IQueryable с Except. Таким образом, все выражение содержит отображенные объекты и может быть переведено в SQL EXCEPT. Другое дело использование Except со списком в памяти. @tvanfosson Я знаю, но есть какое-то исправление: stackoverflow.com/q/24534217/861716. Except (со списком в памяти) выбрасывает "слишком глубоко вложенный" задолго до этих чисел. Можем ли мы сделать вывод, что Except в порядке, если задействованы только отображенные объекты, и что в остальном Contains лучше?
@GertArnold Для примера в этом ответе да. В качестве общего ответа я думаю, что с EF, вероятно, лучше всего сказать «это зависит от обстоятельств» - проверьте свою производительность, выберите стратегию, которая работает лучше всего.
@GertArnold Я обновил ответ, чтобы устранить различные различия. В то время были другие ответы на этот случай, и я не хотел затрагивать ту же тему. Теперь, когда это старый и принятый ответ, я включил этот материал.
Я взял список и использовал,
!MyList.Contains(table.columb.tostring())
Примечание. Убедитесь, что вы используете List, а не Ilist.
У меня есть следующие методы расширения:
public static bool IsIn<T>(this T keyObject, params T[] collection)
{
return collection.Contains(keyObject);
}
public static bool IsIn<T>(this T keyObject, IEnumerable<T> collection)
{
return collection.Contains(keyObject);
}
public static bool IsNotIn<T>(this T keyObject, params T[] collection)
{
return keyObject.IsIn(collection) == false;
}
public static bool IsNotIn<T>(this T keyObject, IEnumerable<T> collection)
{
return keyObject.IsIn(collection) == false;
}
Применение:
var inclusionList = new List<string> { "inclusion1", "inclusion2" };
var query = myEntities.MyEntity
.Select(e => e.Name)
.Where(e => e.IsIn(inclusionList));
var exceptionList = new List<string> { "exception1", "exception2" };
var query = myEntities.MyEntity
.Select(e => e.Name)
.Where(e => e.IsNotIn(exceptionList));
Также очень полезно при прямой передаче значений:
var query = myEntities.MyEntity
.Select(e => e.Name)
.Where(e => e.IsIn("inclusion1", "inclusion2"));
var query = myEntities.MyEntity
.Select(e => e.Name)
.Where(e => e.IsNotIn("exception1", "exception2"));
Это полезно, но не может быть переведено на выражение магазина.
Верно, но я бы хотел выполнить в базе данных. AsEnumerable загрузит данные в память.
Я создал его более похожим на SQL способом, я думаю, что это легче понять
var list = (from a in listA.AsEnumerable()
join b in listB.AsEnumerable() on a.id equals b.id into ab
from c in ab.DefaultIfEmpty()
where c != null
select new { id = c.id, name = c.nome }).ToList();
По какой-то причине
Exceptвыдает ужасный SQL.Contains- это метод, который можно использовать здесь:myEntities.MyEntity.Select(e => e.Name ).Where(x => !exceptionList.Contains(x)).