IndexOf nie dziala w linq

0

Mam taka mala funkcje: (local sql na mobile)

public async Task<List<Product>> GetSearchProductsAsync(string substring)
{
    return await db.Table<Product>().Where(p => p.name.IndexOf(substring, StringComparison.CurrentCultureIgnoreCase) >= 0).ToListAsync();
}

No i nie chce mi przefiltrowac w ten sposob wynikow, blokuje sie na await i tyle.
Jak zmienie na:

.Where(p => p.name.Contains(substring)).ToListAsync();

To dziala ale oczywiscie jest case sensitive.
Z tego co wiem to Contains jest "nakladka" na IndexOf - czy jest mozliwe ze ma cos dopisane zeby dzialalo z async/await?
Albo po prostu juz za duzo przy kompie siedze i cos namieszalem.

Wiadomo ze moge zrobic cos w stylu:

.Where(p => p.name.ToLower().Contains(substring.ToLower()))

ale to brzydko wyglada no i 2x tolower()

Dzieki za pomoc.

1

Generalnie operujesz na obiektach IQueryable, więc nic tu nie jest żadnymi nakładkami tylko jest mapowane na odpowiednie zapytanie SQL. Tu pojawia się pytanie, czy Entity Framework (zakładam że z tego ORMa korzystasz) wspiera metodę IndexOf() - istnieje szansa że nie wspiera i dlatego nie działa. Wydaje mi się tylko, że powinien polecieć wtedy w runtime exception - Tobie natomiast program zawisa.

0

No wlasnie sie nad tym zastanawialem, bo linq ogolnie wspiera ale juz obsluga localSql nie.
Uzywam SQLite.SQLiteAsyncConnection z sqlite-net-pcl Franka Krougera.
Z nakladka chodzi mi o to ze Contains niby uzywa IndexOf (nie jestem tego pewien gdzies mi to przed oczami mignelo) wiec dziwne zeby nieobslugiwalo. (musze pogrzebac i doczytac w wolnej chwili)

1

Jeśli Contains() wewnętrznie używa IndexOf(), to raczej w LINQ no obiektach IEnumerable, ale nie IQueryable, gdzie w natywnym SQL dużo łatwiej jest odwzorować Contains niż IndexOf. W każdym razie, z pewnością jest to wina ORMa, który nie potrafi zmapować tego zapytania LINQ na SQL :) Jeśli zawołasz sobie najpierw ToListAsync(), a dopiero potem Where(), to będzie Ci działać, ale filtrowanie nie będzie miało miejsca w bazie, a w pamięci:

return (await db.Table<Product>().ToListAsync()).Where(p => p.name.IndexOf(substring, StringComparison.CurrentCultureIgnoreCase) >= 0);
0

No w przypadku wywolania najpierw ToList wtedy mi sciagnie calosc a pozniej przefiltruje wiec musze sobie przemyslec bo jestem w sytuacji cos-za-cos.
Albo ToList i zaciagniecie calosci albo ToLower() x2...
Funkcje wywoluje jak user wpisuje w entry kryteria filtrowania -> i filtruje viewListe.
Mam to zrobione na Observable z Rx'a z wlaczonym opoznieniem (co okolo 700ms).
Rekordow w bazie bedzie max 2k (nie zmieniaja sie)... ale co chwile zaciagac calosc zeby tylko przefiltrowac... chyba ze dam jakiegos cache'a

Ale dlaczego Contains dziala na IQueryable a juz IndexOf nie :D moze jednak nie dodali do orm'a.

0

Całości nie zaciągaj, moim zdaniem 2x ToLower() jest spoko, ale jeśli Ci się chce to możesz sprawdzić jaka SQLka finalnie z tego ToLower wychodzi :)

EDIT: Jak trochę poczytałem internety to ToLower() jednak też takie spoko nie jest pod względem performance'u funkcji LOWER w SQLce w którą to się zamienia, ale lepsze opcje chyba nie za bardzo istnieją :D

0

Ale po co ci w ogóle indexof w przypadku tabeli SQL? Jeżeli wiersze w tabeli mają być w jakikolwiek sposób unikalnie ponumerowane to dodaj odpowiednie pole do tabeli.

0

@LagMan: no wlasnie o performance tolower sie boje, bo to jednak mobile, z drugiej strony co raz zaciagac calosc... chyba ze tak jak mowie zrobie jakis cache itp, itd. cos wykombinuje
Zawsze moge dac znormalizowane rekordy "name" w tabeli (np calosc lower albo upper) i wtedy tylko jeden toLower/toUpper, i przy wyswietlaniu capitalize i to jakos wtedy by dzialalo.
@Azarien: w tym przypadku uzywam indexof string'a : to cos zwraca -1 jezeli nie ma substringa w stringu lub jego pozycje jezeli jest, tutaj nic nie ma wspolnego z indexowaniem rekordow w tabeli a jedynie sprawdzanie czy szukany ciag wystepuje w nazwie rekordu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1