LINQ to Entities nie rozpoznaje metody

116

Podczas próby wykonania zapytania linq pojawia się następujący błąd:

LINQ to Entities nie rozpoznaje metody `` Boolean IsCharityMatching (System.String, System.String) '' i tej metody nie można przetłumaczyć na wyrażenie magazynu.

Przeczytałem wiele poprzednich pytań, w których ludzie dostają ten sam błąd i jeśli dobrze to rozumiem, to dlatego, że LINQ to Entities wymaga, aby całe wyrażenie zapytania linq zostało przetłumaczone na zapytanie serwera, a zatem nie można wywołać metody zewnętrznej w tym. Nie byłem w stanie przekształcić mojego scenariusza w coś, co jeszcze działa, a mój mózg zaczyna się topić, więc miałem nadzieję, że ktoś wskaże mi właściwy kierunek. Używamy Entity Framework i wzorca specyfikacji (i jestem nowy w obu).

Oto kod, który używa specyfikacji:

ISpecification<Charity> specification = new CharitySearchSpecification(charityTitle, charityReference);

charities = charitiesRepository.Find(specification).OrderBy(p => p.RegisteredName).ToList();

Oto wyrażenie linq:

public System.Linq.Expressions.Expression<Func<Charity, bool>> IsSatisfied()
{
    return p => p.IsCharityMatching(this.charityName, this.charityReference);
}

Oto metoda IsCharityMatching:

public bool IsCharityMatching(string name, string referenceNumber)
{
    bool exists = true;

    if (!String.IsNullOrEmpty(name))
    {
        if (!this.registeredName.ToLower().Contains(name.ToLower()) &&
            !this.alias.ToLower().Contains(name.ToLower()) &&
           !this.charityId.ToLower().Contains(name.ToLower()))
        {
            exists = false;
        }
    }

    if (!String.IsNullOrEmpty(referenceNumber))
    {
        if (!this.charityReference.ToLower().Contains(referenceNumber.ToLower()))
        {
            exists = false;
        }
    }

    return exists;
}

Daj mi znać, jeśli potrzebujesz więcej informacji.

Wielkie dzięki,

Annelie

Annelie
źródło
sprawdź tę odpowiedź
Eranga
Również to sprawdzę, dzięki!
annelie
1
Byłoby miło zobaczyć, jak używasz, Find()kiedy używasz w IsSatisfied()środku.
Alisson

Odpowiedzi:

124

Jak się zorientowałeś, Entity Framework nie może w rzeczywistości uruchomić kodu C # jako części zapytania. Musi być w stanie przekonwertować zapytanie na rzeczywistą instrukcję SQL. Aby to zadziałało, będziesz musiał zmienić strukturę wyrażenia zapytania na wyrażenie, które może obsługiwać Entity Framework.

public System.Linq.Expressions.Expression<Func<Charity, bool>> IsSatisfied()
{
    string name = this.charityName;
    string referenceNumber = this.referenceNumber;
    return p => 
        (string.IsNullOrEmpty(name) || 
            p.registeredName.ToLower().Contains(name.ToLower()) ||
            p.alias.ToLower().Contains(name.ToLower()) ||
            p.charityId.ToLower().Contains(name.ToLower())) &&
        (string.IsNullOrEmpty(referenceNumber) ||
            p.charityReference.ToLower().Contains(referenceNumber.ToLower()));
}
StriplingWarrior
źródło
1
w razie wątpliwości wyszukaj: stackoverflow.com/questions/2352764/…
Chris Hayes
2
Expression<Func<T,type>>Bardzo fajnym podejściem do tego jest zwrócenie skonstruowanego .
Travis J,
Jak użyłbyś tego w wyrażeniu LINQ? Chciałbym zrobić coś takiego jako klauzulę Where do ponownego wykorzystania, ale mam problemy z jej wdrożeniem.
Zorgarath
4
EDYCJA: nieważne, byłoby:context.Where(IsSatisfied())
Zorgarath
Kluczowa część: „Entity Framework nie może w rzeczywistości uruchomić kodu C # jako części zapytania”
Alper
1

Mam ten sam błąd w tym kodzie:

 var articulos_en_almacen = xx.IV00102.Where(iv => alm_x_suc.Exists(axs => axs.almacen == iv.LOCNCODE.Trim())).Select(iv => iv.ITEMNMBR.Trim()).ToList();

to był dokładnie błąd:

System.NotSupportedException: „LINQ to Entities nie rozpoznaje metody„ Boolean Exists (System.Predicate`1 [conector_gp.Models.almacenes_por_sucursal]) ”i tej metody nie można przetłumaczyć na wyrażenie magazynu.

Rozwiązałem w ten sposób:

var articulos_en_almacen = xx.IV00102.ToList().Where(iv => alm_x_suc.Exists(axs => axs.almacen == iv.LOCNCODE.Trim())).Select(iv => iv.ITEMNMBR.Trim()).ToList();

Dodałem .ToList () przed moją tabelą, co oddziela kod Entity i linq i pozwala uniknąć tłumaczenia mojego następnego wyrażenia linq

UWAGA: to rozwiązanie nie jest optymalne, ponieważ unikaj filtrowania jednostek i po prostu ładuje całą tabelę do pamięci

Inż. Gerardo Sánchez
źródło
1
W większości przypadków jest to najłatwiejsze rozwiązanie, ale aby nie ładować całego obiektu, zwykle dokonuję anonimowego wyboru przed .ToList () tylko tym, czego potrzebuję ... xx.Select (x => new {x.Id, x.DateTimeUpdate }). ToList (). Wybierz (x => new {x.Id, DateTimeUpdate = x.DateTimeUpdate.ToString ("dd / MM / yyyy")})
Diógenes
0

Jeśli ktoś szuka odpowiedzi VB.Net (tak jak ja początkowo), oto ona:

Public Function IsSatisfied() As Expression(Of Func(Of Charity, String, String, Boolean))

Return Function(charity, name, referenceNumber) (String.IsNullOrWhiteSpace(name) Or
                                                         charity.registeredName.ToLower().Contains(name.ToLower()) Or
                                                         charity.alias.ToLower().Contains(name.ToLower()) Or
                                                         charity.charityId.ToLower().Contains(name.ToLower())) And
                                                    (String.IsNullOrEmpty(referenceNumber) Or
                                                     charity.charityReference.ToLower().Contains(referenceNumber.ToLower()))
End Function
Mik
źródło
-1

Miałem podobny problem do twojego, a ta dokumentacja LINQ pomogła mi znaleźć odpowiednie funkcje ciągów do obejścia ograniczeń.

Michael Fayad
źródło