6

Es sieht aus wie die Linq to Entities unterstützt Aggregate Methode. Ich muss diesen Teil des größeren Ausdrucks in etwas umschreiben, das Linq für Entitäten versteht. Ist es möglich?Link zu Entities Aggregate Methode Ersatz

Vielleicht sollte ich Ihnen eine bessere Erklärung geben, was ich mache. Ich muss eine Sammlung von Organisatoren von der Datenbank basierend auf Benutzerberechtigungen zu diesen Organisatoren bekommen. Berechtigungen werden als Bitflags gespeichert und sind eine Kombination der folgenden Optionen:

  1. DefaultOrganizerPermissions - Jeder Veranstalter einige Standardberechtigungen
  2. OwnerPermissions hat - Wenn Benutzer der Besitzer des Veranstalters ist, hat er einige zusätzliche Erlaubnis
  3. UserPermisions - Benutzer können manuell zugewiesen werden, um Berechtigungen für den Organisator zu haben
  4. RolePermissions - Benutzer können Mitglieder von Rollen sein und diesen Rollen können zusätzliche Berechtigungen für Organisatoren zugewiesen werden.

So habe ich eine Methode mit der folgenden Signatur

public IQueryable<Organizer> GetOrganizers(Person person, OrganizerPermissions requiredPermissions)

und im Innern gibt es einen Code wie diese

organizers = organizers.Where(o => ((
     // Default permissions 
     DefaultOrganizerPermissions | 
     // Owner permissions 
     (o.OwnerId == person.Id ? OwnerOrganizerPermissions : 0) | 
     // Personal permissions 
     (o.AccessIdentifier.Accesses.FirstOrDefault(a => a.Accessor is PersonalAccessor && (a.Accessor as PersonalAccessor).PersonId == person.Id) != null ? 
     (OrganizerPermissions)o.AccessIdentifier.Accesses.FirstOrDefault(a => a.Accessor is PersonalAccessor && (a.Accessor as PersonalAccessor).PersonId == person.Id).Permissions : 0) | 
     // Role permissions 
     (o.AccessIdentifier.Accesses.Any(a => a.Accessor is RoleAccessor && (a.Accessor as RoleAccessor).Role.RoleMembers.Any(rm=>rm.PersonId == person.Id)) ? 
     (OrganizerPermissions)o.AccessIdentifier.Accesses.Where(a=> a.Accessor is RoleAccessor && (a.Accessor as RoleAccessor).Role.RoleMembers.Any(rm => rm.PersonId == person.Id)).Select(a=>a.Permissions).Aggregate((a, b) => a | b) : 0) 
     ) & requiredPermissions) == requiredPermissions); 

Vereinfachtes es so etwas wie das ist:

organizers = organizers.Where(o => ((
     DefaultOrganizerPermissions | 
     OwnerOrganizerPermissions | 
     UserPermisions | 
     RolePermissions 
     ) & requiredPermissions) == requiredPermissions); 

Das Problem besteht darin, dass Benutzer Mitglied mehrerer Rollen sein können. Daher sind RolePermissions eigentlich mehrere Berechtigungen, und ich muss sie mit bitweisem ODER reduzieren. Aber wie, wenn Aggregat nicht unterstützt wird?

Antwort

1

Wenn die Datenmenge nicht untragbar groß ist, könnten Sie .ToList() vor dem Select(...) Anweisung aufrufen sollten Sie die Daten in den Speicher zu lesen und dann die Aggregate als Linq durchführen, um Objekte

+0

Ich habe dies schon einmal versucht, aber es hat keine Wirkung. –

+0

Haben Sie das versucht? .... ToList(). Wählen Sie (a => a.Permissions) .Aggregat ((a, b) => a | b) ToList() materialisiert die Abfrage (so ist schlecht) aber es sollte funktionieren ... Sie habe auch andere Möglichkeiten, zB Sum oder wähle nur eine, die wahr ist (FirstOrDefault) aber du solltest expliziter sein. – bubi

+0

@bubi Ja, habe ich. Ich benutze tuList() in einer anderen Methode in der gleichen Klasse und es funktioniert. Aber es funktioniert nicht in diesem. Ich denke, es ist merkwürdig, ich würde erwarten, dass es entweder funktioniert oder einen (anderen) Fehler hervorruft, aber es gibt keine Veränderung. Ich muss nur einige Bit-Flags zusammenführen (sie werden als Ganzzahlen dargestellt), wie zum Beispiel 1010 | 0011 = 1011. Ich weiß nicht, ob es mit Sum möglich ist. –

0

Wenn Berechtigungen ist NULL festlegbare Sie wahrscheinlich brauchen einfügen
a.Permissions.GetValueOrDefault()
so sollte die Abfrage
.Select (a => a.Permissions.GetValueOrDefault()) sein Aggregate ((a, b) => a | b).

Auch, wenn der EF-Provider nicht unterstützt Aggregierte Übersetzung in SQL (dieser Teil ist Provider-spezifisch, so dass er mit einem DBMS arbeiten kann, aber nicht mit einem anderen DBMS) Sie müssen die Abfrage mit ToList() materialisieren (wie von @sjager vorgeschlagen).

EDIT
Das Problem ist, dass EF-Anbieter nicht Aggregate Übersetzung SQL unterstützt.

Ich bin kein SQL Server-Experte sowieso sollten Sie eine Aggregat Funktion finden (wie SUM oder AVG), die macht, was Sie brauchen (bitweises ODER). In MySQL ist BIT_OR().

Wenn es nicht existiert dann GAME OVER

Wenn es vorhanden ist können Sie den Quellcode von EF-Provider für SQL Server und das Anzeigen Wich LINQ Funktion übersetzt wird in dieser Ansicht oder fragen einen anderen Frage-

+0

Berechtigungen in nicht nullbar, es hat immer einen Wert. Ich kann den Aggregatteil nach der ToList() erfolgreich ausführen, wenn es die letzte Anweisung der Ausdrucksbaumstruktur ist. Aber ich muss es als Teil einer größeren Abfrage ausführen, d. H. In der Mitte des Ausdrucksbaums, das ist das Problem. –

+0

Was ist die Ausnahme, wenn Sie ToList nicht einfügen? Oder ist SQL Server das Problem? In diesem Fall können Sie die Abfrage verfolgen und versuchen, sie auf SQL Server auszuführen und zu sehen, was passiert. – bubi

+0

Es ist eine Ausnahme vom Typ 'System.NotSupportedException' in EntityFramework.SqlServer.dll aufgetreten, wurde aber nicht im Benutzercode behandelt Zusätzliche Informationen: LINQ to Entities erkennt die Methode 'Int32 Aggregate [Int32] (System.Collections .Generic.IEnumerable''1 [System.Int32], System.Func''3 [System.Int32, System.Int32, System.Int32]) "Methode, und diese Methode kann nicht in einen Ausdruck übersetzt werden." Link zu Entitäten wissen einfach nicht, wie man die Aggregate-Methode in SQL übersetzt. –

0

Überraschenderweise Ich bin gestern genau in die gleiche Situation gerannt. Also, wie @Bubi erklärte, ohne SQL Server ordnungsgemäße Aggregatfunktion ist es nicht möglich.

Die Art, wie ich daran gearbeitet habe, ist - Erstellen Sie eine Reihe von OR-Ausdrücke Gruppen für jede Rolle, von denen jede einen Vergleich mit einer Rolle des Benutzers hat. Verbinden Sie anschließend alle "ODER-Ausdrucksgruppen" mit dem UND-Prädikat.

z. Wenn der Benutzer den Wert von 0011 enum hat, müssen Sie OR-Vergleichselemente für die Flags 0001 und 0010 erstellen. 0001-Flag "OR-Gruppe" würde aussehen wie

x=> x.Equals(0001) || x.Equals(0011) || x.Equals(0101)| || ..) 

Aber es ist definitiv nicht zu empfehlen.