Где элемент IN в структуре сущности Framework [дубликат]

Одна проблема, которую он решает: Код проще, чем lambda для вызова в конструкторе, который использует функцию выходного параметра для инициализации члена const

Вы можете инициализировать член const вашего класс, с вызовом функции, которая устанавливает его значение, возвращая свой вывод в качестве выходного параметра.

205
задан shA.t 30 December 2015 в 07:28
поделиться

8 ответов

Вам нужно повернуть его на голову с точки зрения того, как вы думаете об этом. Вместо того, чтобы делать «в», чтобы найти права пользователя текущего элемента в предопределенном наборе применимых прав пользователя, вы запрашиваете предопределенный набор прав пользователя, если он содержит применимое значение текущего элемента. Это точно так же, как вы бы нашли элемент в обычном списке в .NET.

Существует два способа сделать это с помощью LINQ, один использует синтаксис запроса, а другой использует синтаксис метода. По существу, они одинаковы и могут использоваться взаимозаменяемо в зависимости от ваших предпочтений:

Синтаксис запроса:

var selected = from u in users
               where new[] { "Admin", "User", "Limited" }.Contains(u.User_Rights)
               select u

foreach(user u in selected)
{
    //Do your stuff on each selected user;
}

Метод Синтаксис:

var selected = users.Where(u => new[] { "Admin", "User", "Limited" }.Contains(u.User_Rights));

foreach(user u in selected)
{
    //Do stuff on each selected user;
}

Мое личное предпочтение в этом случае может быть синтаксисом метода, потому что вместо назначения переменной я мог бы сделать foreach над анонимным вызовом, подобным этому:

foreach(User u in users.Where(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
    //Do stuff on each selected user;
}

Синтаксически это выглядит более сложным, и вы должны понимать концепцию лямбда-выражений или делегатов, чтобы действительно понять, что происходит, но, как вы можете видеть, это скомпенсирует код с достаточной суммой.

It все сводится к вашему стилю кодировки и предпочтениям - все три моих примера делают то же самое несколько иначе.

Альтернативный способ даже не использует LINQ, вы можете использовать тот же синтаксис метода, который заменяет «где», с «FindAll» и получить тот же результат, который также будет работать в .NET 2.0:

foreach(User u in users.FindAll(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
    //Do stuff on each selected user;
}
320
ответ дан Luke Girvin 15 August 2018 в 15:35
поделиться
  • 1
    возможно, я был слишком быстр, чтобы отметить как ответ, но я не получаю. Консоли после {& quot; Admin & quot ;, & quot; User & quot ;, & quot; Limited & quot; } VS2008 не нравится этот код один бит. – StevenMcD 13 May 2009 в 14:51
  • 2
    верный моему имени & quot; FailBoy & quot; Я понял: P я ввел строку [], а затем использовал ее, и она сработала. Благодаря! – StevenMcD 13 May 2009 в 14:56
  • 3
    извините, я забыл новый анонимный массив;) Я исправил свой пример кода. Рад, что вы сами это поняли. – BenAlabaster 13 May 2009 в 15:07
  • 4
    Этот ответ был бы правильным, если бы речь шла о Linq-to-SQL или Linq в целом. Однако, поскольку он конкретно говорит «Linq-to-Entities», этот ответ неверен. array.Contains пока не поддерживается Linq-to-Entities. – KristoferA 29 May 2009 в 08:04
  • 5
    @KristoferA - возможно, это было верно для более ранних версий EF, но для меня это отлично подходит для EF4. – Drew Noakes 7 May 2011 в 18:55

Серьезно? Вы никогда не пользовались

where (t.MyTableId == 1 || t.MyTableId == 2 || t.MyTableId == 3)
-11
ответ дан animuson 15 August 2018 в 15:35
поделиться
  • 1
    -1 Попробуйте это с 20 или более значениями в таблице с более чем 1000 строк, и вы быстро увидите преимущество принятого решения. Кроме того, не легко добавить произвольное количество условий в оператор where (например, если пользователь выбирает включить опции 1 и 2, но не 3). – Trisped 4 April 2013 в 01:55
  • 2
    Ну, мне не нужен был какой-то сумасшедший ученый, и этот ответ проголосовал за меня, потому что мне нужны были AND и 2 ORS var SamplePoints = (из c в _db.tblPWS_WSF_SPID_ISN_Lookup.OrderBy (x = & gt; x.WSFStateCode), где c .PWS == id & amp; & amp; ((c.WSFStateCode.Substring (0, 2) == "SR") || (c.WSFStateCode.Substring (0, 2) == "CH")) select с) .ToList (); – JustJohn 3 November 2014 в 22:55
  • 3
    @Trisped - количество строк (1000) ничего не меняет - или я что-то пропустил? – tymtam 8 September 2016 в 22:08
  • 4
    @Tymski Да, количество строк имеет значение. Чем больше строк, тем больше вычислений. То же самое с количеством возможных значений: Checks = NumValues * NumRows. Поскольку это расчет типа M * N, если он мал, тогда время выполнения каждой требуемой проверки также будет небольшим. Я добавил ограничение, поэтому cjm30305 будет знать, как настроить тестовую среду, где показано, почему его решение плохое. – Trisped 18 September 2016 в 17:59
  • 5
    @Trisped Вы говорите, что where new[] { 1, 2, 3 }.Contains(x) делает меньше сравнений тогда where (x == 1 || x == 2 || x == 3)? – tymtam 19 September 2016 в 22:19

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

fea_Features.Where(s => selectedFeatures.Contains(s.feaId))
18
ответ дан Balaji Birajdar 15 August 2018 в 15:35
поделиться

Если вы используете VS2008 / .net 3.5, см. подсказку Alex James № 8: http://blogs.msdn.com/alexj/archive/2009/03/26/tip-8-writing -where-in-style-queries-using-linq-to-entities.aspx

В противном случае просто используйте метод array.Contains (someEntity.Member).

9
ответ дан KristoferA 15 August 2018 в 15:35
поделиться
  • 1
    Пожалуйста, избегайте использования ссылок только для ответов, вы должны суммировать содержимое ссылки в своем ответе, в случае, если связь будет нарушена в будущем. – user 24 March 2014 в 10:18
  • 2
    [Д0] web.archive.org/web/20100701174329/http://blogs.msdn.com/b/… – KristoferA 31 March 2014 в 13:02

Я также пытался работать с подобной SQL-IN-вещью - запросом на модель данных сущности. Мой подход - строковый построитель для создания большого OR-выражения. Это ужасно уродливо, но я боюсь, что это единственный способ пойти прямо сейчас.

Теперь хорошо, это выглядит так:

Queue<Guid> productIds = new Queue<Guid>(Products.Select(p => p.Key));
if(productIds.Count > 0)
{
    StringBuilder sb = new StringBuilder();
    sb.AppendFormat("{0}.ProductId = Guid\'{1}\'", entities.Products.Name, productIds.Dequeue());
    while(productIds.Count > 0)
    {
        sb.AppendFormat(" OR {0}.ProductId = Guid\'{1}\'",
          entities.Products.Name, productIds.Dequeue());
    }
}

Работа с GUID в этом контексте: Как вы можете видеть выше, всегда есть слово «GUID» перед GUID ifself в фрагментах строки запроса. Если вы не добавите это, ObjectQuery<T>.Where выдает следующее исключение:

Типы аргументов «Edm.Guid» и «Edm.String» несовместимы для этой операции., Near equals expression , строка 6, столбец 14.

Обнаружено это в форумах MSDN, может быть полезно иметь в виду.

Matthias

... с нетерпением жду следующей версии .NET и Entity Framework, когда все станет лучше. :)

2
ответ дан Matthias Meid 15 August 2018 в 15:35
поделиться

В этом контексте я поеду на Inner Join. Если бы я использовал contains, он бы итерации 6 раз, несмотря на тот факт, что существует только одно совпадение.

var desiredNames = new[] { "Pankaj", "Garg" }; 

var people = new[]  
{  
    new { FirstName="Pankaj", Surname="Garg" },  
    new { FirstName="Marc", Surname="Gravell" },  
    new { FirstName="Jeff", Surname="Atwood" }  
}; 

var records = (from p in people join filtered in desiredNames on p.FirstName equals filtered  select p.FirstName).ToList(); 

Недостатки Contains

Предположим, у меня есть два объекта списка.

List 1      List 2
  1           12
  2            7
  3            8
  4           98
  5            9
  6           10
  7            6

Используя Contains, он будет искать каждый элемент List 1 в списке 2, что означает, что итерация произойдет 49 раз !!!

5
ответ дан Pankaj 15 August 2018 в 15:35
поделиться
  • 1
    Это полностью игнорирует тот факт, что оператор преобразуется в SQL. См. здесь . – Gert Arnold 10 August 2015 в 22:23

Это может быть возможный способ непосредственного использования методов расширения LINQ для проверки предложения in

var result = _db.Companies.Where(c => _db.CurrentSessionVariableDetails.Select(s => s.CompanyId).Contains(c.Id)).ToList();
3
ответ дан shA.t 15 August 2018 в 15:35
поделиться

Альтернативный метод ответа BenAlabaster

Прежде всего, вы можете переписать запрос следующим образом:

var matches = from Users in people
        where Users.User_Rights == "Admin" ||
              Users.User_Rights == "Users" || 
              Users.User_Rights == "Limited"
        select Users;

Конечно, это более «многословно» и больно писать но он работает все равно.

Итак, если бы у нас был какой-то метод утилиты, который упростил создание таких выражений LINQ, мы бы были в бизнесе.

с помощью метода утилиты на месте вы можете написать что-то вроде этого:

var matches = ctx.People.Where(
        BuildOrExpression<People, string>(
           p => p.User_Rights, names
        )
);

Это создает выражение, которое имеет такой же эффект, как:

var matches = from p in ctx.People
        where names.Contains(p.User_Rights)
        select p;

Но что более важно, фактически работает с .NET 3.5 SP1.

Вот функция сантехники, которая делает это возможным:

public static Expression<Func<TElement, bool>> BuildOrExpression<TElement, TValue>(
        Expression<Func<TElement, TValue>> valueSelector, 
        IEnumerable<TValue> values
    )
{     
    if (null == valueSelector) 
        throw new ArgumentNullException("valueSelector");

    if (null == values)
        throw new ArgumentNullException("values");  

    ParameterExpression p = valueSelector.Parameters.Single();

    if (!values.Any())   
        return e => false;

    var equals = values.Select(value =>
        (Expression)Expression.Equal(
             valueSelector.Body,
             Expression.Constant(
                 value,
                 typeof(TValue)
             )
        )
    );
   var body = equals.Aggregate<Expression>(
            (accumulate, equal) => Expression.Or(accumulate, equal)
    ); 

   return Expression.Lambda<Func<TElement, bool>>(body, p);
}

Я не собираюсь пытаться объяснить этот метод, кроме как сказать, что он по существу строит предикат выражение для всех значений с помощью значенияSelector (т.е. p => p.User_Rights) и ORs, которые предикаты вместе создают выражение для полного предиката

Источник: http: //blogs.msdn. ком / б / AlexJ / архив / 2009/03/26 / наконечник-8-писание-где-в-стиле-запросов-using- LINQ к entities.aspx

1
ответ дан Shaegorath 15 August 2018 в 15:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: