2015-03-20 3 views
0

У меня есть что-то вроде этого:Вызов метода внутри LINQ

var adrsQuery = (from a in this.Context.Addresses 
      where myList.Contains(a.Address_K) 
      select new AlternateAddressesDB() 
      { 
       Line1 = GetAddressLine1(a.AddressLine1), 
       Line2 = a.AddressLine2, 
       City = a.City, 
       State = a.State, 
       ZipCode = a.ZipCode 
      }).ToList(); 


     private static string GetAddressLine1(string adrs) 
     { 
      if (string.IsNullOrWhiteSpace(adrs)) 
       adrs = "Medical Office"; 

      return adrs; 
     } 

Проблема в Line1 = GetAddressLine1(a.AddressLine1), Похоже, я не могу назвать метод там, как я могу сделать эту логику, что я имею в метод, не называя его так?

+0

Что значит «Похоже, что я не может вызвать метод там "? – MyCodeSucks

+0

@MyCodeSucks, потому что он падает во время выполнения !!! – Bohn

+0

Какая ошибка? – MyCodeSucks

ответ

4

Другие уже объяснили вам эту проблему. Вы не можете выполнять методы C# на сервере SQL ...

Обычно вы пытаетесь изменить свой запрос:

var adrsQuery = (from a in this.Context.Addresses 
     where myList.Contains(a.Address_K) 
     select new AlternateAddressesDB() 
     { 
      Line1 = a.AddressLine1 == null || a.AddressLine1.TrimEnd() == string.Empty ? "Medical Office" : a.AddressLine1, 
      Line2 = a.AddressLine2, 
      City = a.City, 
      State = a.State, 
      ZipCode = a.ZipCode 
     }).ToList(); 

или вы вынуждаете выполнение Вашего метода локально:

var adrsQuery = (from a in this.Context.Addresses 
     where myList.Contains(a.Address_K) 
     select new AlternateAddressesDB() 
     { 
      Line1 = a.AddressLine1, 
      Line2 = a.AddressLine2, 
      City = a.City, 
      State = a.State, 
      ZipCode = a.ZipCode 
     }) 

     .AsEnumerable() // From here the query is executed "locally" 

     .Select(a => new AlternateAddressesDB() 
     { 
      Line1 = GetAddressLine1(a.Line1), 
      a.Line2, 
      a.City, 
      a.State, 
      a.ZipCode 
     }) 
     .ToList(); 

Вы загружаете из БД нужные вам данные, а затем локально создаете новый набор объектов с данными «манипулировали»

(это второе решение обычно можно использовать только в финале .Select(), потому что если вы выполняете полную .Where() локально, вы просите слишком много строк на сервер, а затем вы пропускаете многие из них)

Существует второй/третий вариант: https://stackoverflow.com/a/29128874/613130 несколько дней назад они попросили мне как решить подобную проблему. Посмотрите на примеры, которые я дал с решением. Ограничением является то, что вам нужно, чтобы иметь возможность конвертировать метод команд, которые могут быть выполнены с помощью Entity Framework (так что вам нужно будет преобразовать .IsNullOrWhiteSpace() к чему-то, что может быть отправлен в SQL), как:

[Expandable] 
static string GetAddressLine1(Address address) 
{ 
    // Not necessary to implement, see linked answer 
    throw new NotImplementedException(); 
} 

static Expression<Func<Address, string>> GetAddressLine1Expression() 
{ 
    return x => x.AddressLine1 == null || x.AddressLine1.TrimEnd() == string.Empty ? "Medical Office" : x.AddressLine1; 
} 

Обратите внимание, что эта дорога намного сложнее, и я не предлагаю ее слабому сердцу или тем, кто может следовать за более простыми дорогами (я лично их не использую)

+0

почему люди проголосовали за это? это неправильно? – Bohn

+0

+1 для разных подходов. Тем не менее, AsEnumerable() до выбора оператора достаточно для ситуации, подобной @Jodrell. – ambitiouz

4

Проблема не в LINQ. Вы используете ORM, который преобразует LINQ, который вы пишете в SQL. Он не может переводить вызовы произвольных методов. Вы должны будете сделать преобразование в результате запроса.

Итак - получи результаты без пытается позвонить GetAddressLine1 inline. Затем вы можете использовать Select проецировать результаты снова, чтобы исправить свои данные ... например:

var adrsQuery = this.Context.Addresses 
.Where(a => myList.Contains(a.Address_K)) 
.AsEnumerable() 
.Select(a => new AlternateAddressesDB 
    { 
     Line1 = GetAddressLine1(a.AddressLine1), 
     Line2 = a.AddressLine2, 
     City = a.City, 
     State = a.State, 
     ZipCode = a.ZipCode 
    }).ToList(); 


private static string GetAddressLine1(string adrs) 
{ 
    if (string.IsNullOrWhiteSpace(adrs)) 
     adrs = "Medical Office"; 

    return adrs; 
} 
+0

Не могли бы вы объяснить больше? Как насчет этого тройного оператора? Могу ли я так поступать? как показано ниже: Line1 = string.IsNullOrWhiteSpace (a.AddressLine1)? «Медицинский офис»: a.AddressLine1; – Bohn

2

Я должен ключ это this.Context который я полагаю некоторые ОРМ. Таким образом, ваш запрос linq переводится в sql и не может содержать вызовы методов. Но ваш метод достаточно прост, вы можете встраивать логику в запросе

a.AddressLine1 ?? "value" 

И да его не совсем то же самое, но вы получите идею.

+0

хорошо как об этом? Line1 = string.IsNullOrWhiteSpace (a.AddressLine1)? «Медицинский офис»: a.AddressLine1; – Bohn

+0

Я не могу точно сказать, будет ли это работать, но проверить его достаточно легко. – Rafal

+1

'IsNullOrWhiteSpace' не будет работать, но вы можете, конечно, просто сделать' (a.AddressLine1 == null || a.AddressLine1.Trim() == string.Empty)? «Медицинский офис»: a.AddressLine1' – sloth

3

ли это так,

var adrsQuery = this.Context.Addresses 
    .Where(a => myList.Contains(a.Address_K)) 
    .ToList() // This line executes the IQueryable and returns an IEnumerable. 
    .Select(a => new AlternateAddressesDB 
     { 
      Line1 = GetAddressLine1(a.AddressLine1), 
      Line2 = a.AddressLine2, 
      City = a.City, 
      State = a.State, 
      ZipCode = a.ZipCode 
     }).ToList(); 


    private static string GetAddressLine1(string adrs) 
    { 
     if (string.IsNullOrWhiteSpace(adrs)) 
      adrs = "Medical Office"; 

     return adrs; 
    } 

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

Смежные вопросы