Выберите, где свойство модели содержит все в списке пар ключ-значение

У меня есть следующий класс

public class Account
{
    IEnumerable<AccountData> Data { get; set; }
}

где AccountData

public class AccountData
{
    public virtual long Id { get; set; }
    public virtual AccountTag AccountTag { get; set; }
    public virtual string Value { get; set; }
}

и где тег учетной записи

public class AccountTag
{
    public virtual long Id { get; set; }
    public virtual string Name { get; set; }
}

Я хочу вернуть все учетные записи, где поле данных находится в списке пар ключ-значение. long — это AccountTag.Id, а AccountData.Value содержит строку

Вот что у меня есть до сих пор, но это выполняется на веб-сервере, и могут быть возвращены тысячи учетных записей, поэтому я ищу версию linq to sql.

public IEnumerable<Account> FindByCompanyDataTags(long companyId, IEnumerable<KeyValuePair<long, string>> tags)
{
    var tempAccounts = (from acc in this.Data where acc.Company.Id == companyId orderby acc.Name select acc);
    IList<Account> accounts = new List<Account>();

    foreach (var account in tempAccounts)
    {
       var matches = true;
       foreach (var t in tags)
       {
          if (account.Data.Any(x => x.AccountTag.Id == t.Key && x.Value.Contains(t.Value)))
          {
            continue;
          }

          matches = false;
          break;
        }

        if (matches)
        {
          accounts.Add(account);
        }
      }

      return accounts;
}

Если я использую resharper для преобразования этого в выражение linq, я получаю следующее

public IEnumerable<Account> FindByCompanyDataTags(long companyId, IEnumerable<KeyValuePair<long, string>> tags)
{
  var tempAccounts = (from acc in this.Data where acc.Company.Id == companyId orderby acc.Name select acc);
  IList<Account> accounts = (from account in tempAccounts let matches = tags.All(t => account.Data.Any(x => x.AccountTag.Id == t.Key && x.Value.Contains(t.Value))) where matches select account).ToList();

  return accounts;
}

Но когда я запускаю это, я получаю исключение, не поддерживаемое методом.

Это действительно сбивает меня с толку, есть предложения?


person JConstantine    schedule 20.01.2012    source источник
comment
Это Linq-to-NHibernate или Linq-to-SQL?   -  person Groo    schedule 21.01.2012
comment
Хороший улов, это linq для nhibernate   -  person JConstantine    schedule 21.01.2012
comment
Да, поставщик NH LINQ все еще не полностью реализован (хотя я не уверен, что даже EF так хорошо обрабатывает сложные запросы). Если вы можете использовать HQL, вы получите лучшие результаты. Вот почему мы, тем не менее, используем шаблон Repository с NH, чтобы при необходимости можно было легко вручную создать некоторые специфические операции. Когда вы предоставляете свои данные как IQueryable, вы должны быть уверены, что LINQ to NHibernate сможет правильно перевести все ваши запросы (а это не так).   -  person Groo    schedule 21.01.2012


Ответы (1)


Это происходит потому, что в первом случае вы готовите запрос к БД во время выполнения foreach здесь

foreach (var account in tempAccounts)
{....}

Вы получаете коллекцию объектов Account и работаете с ними на стороне клиента в памяти (другими словами, вы используете Linq для объектов)

Во втором случае вы пытаетесь выполнить запрос Linq to Sql, но провайдер не может перевести работу с вашими KeyValuePair объектами в sql-запрос, поэтому об этом говорится в исключении.

ОБНОВЛЕНИЕ

Попробуйте использовать IQueryable и построить свой запрос, последовательно применяя предложение Where:

IQueryable<Account> tempAccountsWithWhere = tempAccounts;
foreach (var tag in tags)
{
    tempAccountsWithWhere = tempAccountsWithWhere.Where(
        a => a.Data.Any(
            ad => ad.AccountTag.Id == tag.Key && ad.Value.Contains(tag.Value)));
}
IList<Account> accounts = tempAccountsWithWhere.ToList();
person WarHog    schedule 20.01.2012
comment
Согласен, первый случай не самый лучший, поэтому я хочу использовать второй сценарий. Есть ли альтернатива, которая не будет генерировать исключение и обеспечивает лучшую производительность? - person JConstantine; 21.01.2012