2009-09-15 9 views
4

J'ai un [Flags] ENUM comme ceci:Comment utiliser flags enums dans les requêtes Linq to Entities?

[Flags] 
public enum Status 
{ 
    None = 0, 
    Active = 1, 
    Inactive = 2, 
    Unknown = 4 
} 

Un ENUM d'état peut contenir deux valeurs telles que:

Status s = Status.Active | Status.Unknown; 

Maintenant, je dois créer une requête LINQ (LINQ to ADO.NET Entités) et demander des enregistrements dont le statut est s ci-dessus, c'est-à-dire Actif ou Inconnu;

var result = from r in db.Records 
      select r 
      where (r.Status & (byte)s) == r.Status 

Bien sûr, j'obtiens une erreur, car LINQ to Entities ne sait gérer que les types primitifs dans la clause Where.

L'erreur est:

Impossible de créer une valeur constante de type 'type de fermeture. Seuls les types primitifs ('tels que Int32, String et Guid') sont pris en charge dans ce contexte.

Existe-t-il un moyen pratique? Je peux avoir un statut Enum avec 10 valeurs possibles et interroger 5 des statuts. Comment puis-je construire la requête en utilisant Flags enum d'une manière élégante?

Merci.

Mise à jour

Cela semble être un problème LINQ to Entities. Je pense que dans LINQ to SQL cela fonctionne (pas sûr, n'a pas testé).

+0

Vous êtes question (si cela a fonctionné) ne retournerait que les enregistrements dont le statut est simultanément 'Active' * et *' Unknown'. Est-ce que c'est ce que tu veux? – LukeH

+0

Non, c'était un OU pas un ET. Donc 'Statut s = Statut.Actif | Statut inconnu;' est correct. Merci! –

+0

@Vasi: Cette partie est correcte, mais "Status.Active | Status.Unknown'" est équivalent à "' 1 | 4' "qui est' 5'. Donc, votre clause 'where' dit effectivement" 'where (r.Status & 5) == r.Status'", qui est la même chose que "' where r.Status == 5' ", ce qui équivaut à dire (en anglais) "où' r.Status' est à la fois 'Active' * et *' Unknown' "! – LukeH

Répondre

0

Je ne sais pas EF, mais pourrait insérer des moulages supplémentaires?

var result = from r in db.Records 
      where ((byte)r.Status & (byte)s) == (byte)r.Status 
      select r 
+0

r. Le statut est octet déjà, et j'ai ajouté la distribution dans la question aussi. Ce n'est pas le problème, le problème est qu'il ne fonctionnera pas. Il compile mais ne fonctionne pas. Voir l'erreur dans la question. –

0

Essayez comme ceci:

byte status = (byte)(Status.Active | Status.Unknown); 

var result = from r in db.Records 
      select r 
      where (r.Status & status) != 0 
+0

Je pense que l'évaluation dans Où n'est pas traduisible en esql ou somethong comme ça. C'est pourquoi je reçois l'exception: "Impossible de créer une valeur constante de type 'Type de fermeture' Seuls les types primitifs ('tels que Int32, String et Guid') sont pris en charge dans ce contexte." –

+0

@Vasi: Oui, mais avez-vous cette erreur avec ma version? – LukeH

+0

J'ai la même erreur. –

1
var result = from r in db.Records 
      where r.Status == s 
      select r 
0

Je ne suis pas sûr si Bitwise opération ET travailleront, mais essayez casting s à un int:

 int i = (int)s; 
     var result = from r in db.Records 
      select r 
      where (r.Status & i) == r.Status 

qui moteur de base de données utilisez-vous? Peut-être que le moteur ne prend pas en charge les opérations au niveau du bit.

Référence: http://www.matthidinger.com/archive/2008/02/26/entity-framework-comparison-frustration-explained.aspx

+0

Utilisation de LINQ to Entities sur un serveur MS SQL Server. –

+0

Ce n'est pas un problème de moulage. –

+0

Non, il est impossible de traduire le résultat de l'énumération en un type SQL natif. Ainsi, l'utilisation d'une comparaison entière pourrait fonctionner. –

0

Le folloiwng travaille pour moi en C#

public const StatusTypes ActiveAlert = StatusTypes.Accepted | StatusTypes.Delivered; 

     int flags = (int)ActiveAlert; 

     try 
     { 
      var query = from p in model.AlertsHistory 
         where (p.UserId == clientId 
         && (p.Status.HasValue && (p.Status.Value & flags) != 0)) 
         select p; 
      var aList = query.ToList(); 

      return (aList); 


     } 
     catch (Exception exc) 
     { 
      log.Error("Exception getting Alerts History for user.", exc); 
      throw; 
     } 
3

Il suffit d'utiliser HasFlag()

var result = from r in db.Records 
     where r.Status.HasFlag(s) 
     select r 
0

Dans DB Drapeaux ENUM doit être un entier. Après cela, vous pouvez l'essayer comme ceci:

Status s = Status.Active | Status.Unknown; 

var result = from r in db.Records 
where (s & r.Status) == r.Status 
select r 
Questions connexes