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?
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"));
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);
}
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.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);
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));
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