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

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

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

, а где Account Tag *

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

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

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

1 Ответ

1 голос
/ 21 января 2012

Это происходит потому, что в первом случае вы подготавливаете запрос к БД во время 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();
...