Tworzenie wspólnej funkcji predykatu

Po pierwsze, nie jestem pewien, jakich terminów użyć, aby zadać to pytanie, i prawdopodobnie dlatego sam nie znalazłem odpowiedzi na to pytanie.

Więc pracuję z Linq do SQL (C#,. Net 4) i chcę uzyskać listę wszystkich użytkowników, którzy spełniają kryteria, których podstawy zrobiłbym coś takiego:

var users = DataContext.Users.Where(x => x.Criteria1 == "something");

Ale w tym przypadku jest kilka pól, które chcę dopasować, rzecz w tym, że te konkretne pola są wspólnym czekiem i chciałbym móc utworzyć dedykację funkcja, której mogę użyć w dowolnym z moich zapytań użytkownika, aby sprawdzić to dopasowanie.

Aby spróbować wyjaśnić, że nieco lepiej podajmy przykład: powiedzmy, że użytkownik ma 5 FLAG, I chcę wspólnego sprawdzenia, czy jakiekolwiek z tych flag są ustawione. Więc mógłbym napisać moje zapytanie w ten sposób:

var users = DataContext.Users.Where(x => x.Flag1 || x.Flag2 || x.Flag3 || x.Flag4 || x.Flag5);

Ale to, co chciałbym zrobić, to oddzielić to "5 FLAG check", więc mogę go używać również w innych zapytaniach, ostatecznie chciałbym użyć czegoś w stylu:

var users = DataContext.Users.Where(x => x.Criteria1 == "something" && CheckForFlags(x));

Próbowałem tego przez funkcja taka:

static bool CheckForFlags(User user)
{
   return user.Flag1 || user.Flag2 || user.Flag3 || user.Flag4 || user.Flag5;
}

Ale dostaję błąd:

"Metoda' Boolean CheckForFlags (User) ' nie ma obsługiwanego tłumaczenia na SQL."

...co ma sens, ale jest coś, co mogę zrobić, aby to działało tak, jak chcę? Czy jest to ograniczenie, ponieważ używam Linq do SQL i jest w rzeczywistości czymś, co działa z LINQ to Objects?

Author: Mario Sannum, 2012-11-01

5 answers

Fajną rzeczą w tym, jak LINQ do SQL obsługuje wyrażenia jest to, że możesz tworzyć wyrażenia w innym miejscu w kodzie i odwoływać się do nich w zapytaniach. Może spróbujesz czegoś takiego:

public static class Predicates
{
    public static Expression<Func<User, bool>> CheckForFlags()
    {
        return (user => user.Flag1 || user.Flag2 || user.Flag3 ||
                        user.Flag4 || user.Flag5);
    }

    public static Expression<Func<User, bool>> CheckForCriteria(string value)
    {
        return (user => user.Criteria1 == value);
    }
}

Po zdefiniowaniu predykatów, bardzo łatwo jest ich użyć w zapytaniu.

var users = DataContext.Users
    .Where(Predicates.CheckForFlags())
    .Where(Predicates.CheckForCriteria("something"));
 39
Author: Adam Maras,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-01 16:24:06

Próbowałeś PredicateBuilder? Nie używałem go od ponad roku, ale stwierdziłem, że jest skuteczny podczas pisania zapytań "lub gdzie".

Http://www.albahari.com/nutshell/predicatebuilder.aspx

Przykład z ich strony:

IQueryable<Product> SearchProducts (params string[] keywords)
{
  var predicate = PredicateBuilder.False<Product>();

  foreach (string keyword in keywords)
  {
    string temp = keyword;
    predicate = predicate.Or (p => p.Description.Contains (temp));
  }
  return dataContext.Products.Where (predicate);
}
 4
Author: JoshVarty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-01 16:10:49

Według mojej najlepszej wiedzy są dwa możliwe sposoby, aby to zrobić.

Quick-n-easy sposobem jest filtrowanie wyników po wykonaniu SQL, z czymś takim:

var users = DataContext.Users.Where(x => x.Criteria1 == "something");
    .ToEnumerable()
    .Where(x => CheckForFlags(x));

Jest to jednak bardzo słabe pod względem wydajności. Zwróci wszystkie wiersze z bazy danych pasujące tylko do pierwszych kryteriów, a następnie filtruje wyniki w pamięci na kliencie. Funkcjonalny, ale daleki od optymalnego.

Drugą, o wiele bardziej wydajną opcją jest utworzenie UDF na sama baza danych i wywołaj ją z LINQ. Zobacz na przykład to pytanie . Oczywistym minusem jest to, że przenosi kod do bazy danych, czego nikt nie lubi (z wielu ważnych powodów).

Mogą być inne realne rozwiązania, ale tylko o nich wiem.
 0
Author: ean5533,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:09:17

I think this will work, and I think I 've used it in my Linq-to-SQL project, but I can' t find an example offhand. Jeśli nie, daj mi znać.


Zamiast tworzenia funkcji, Utwórz nową właściwość na obiekcie Users:

partial class Users {
   bool CheckForFlags
    {
       get { 
          return Flag1 || Flag2 || Flag3 || Flag4 || Flag5;
       }
    }
}

Wtedy powinieneś być w stanie zrobić

var users = DataContext.Users.Where(x => x.CheckForFlags);
 0
Author: Bobson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-01 16:16:03

Jak powiedziałeś, jest to ograniczenie, ponieważ używasz Linq do SQL.

Coś takiego powinno działać:

var users = DataContext.Users.Where(x => x.Criteria1 == "something")
                             .ToArray()
                             .Where(x => CheckForFlags(x));
 -1
Author: RobSiklos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-01 16:04:16