2008-12-18 8 views
6

Je rencontre des problèmes lors de l'utilisation de la méthode d'extension OrderBy sur une requête LINQ lorsqu'elle fonctionne sur un type enum. J'ai créé un DataContext régulier en utilisant Visual Studio en faisant simplement glisser et déposer tout sur le concepteur. J'ai ensuite créé des modèles d'entité séparés, qui sont simplement des POCO, et j'ai utilisé un modèle de référentiel pour extraire les données de ma base de données et les mapper dans mes propres modèles d'entité (ou plutôt, j'ai un modèle de référentiel qui construit et IQueryable ça va faire tout ça).Linq To SQL OrderBy, problème lors de l'utilisation d'enums

Tout fonctionne très bien, sauf lorsque j'essaie d'appliquer un OrderBy (en dehors du référentiel) sur une propriété que j'ai mappée de short/smallint à enum.

Voici les bits de code correspondant:

public class Campaign 
{ 
    public long Id { get; set; } 
    public string Name { get; set; } 
    .... 
    public CampaignStatus Status { get; set; } 
    ... 
} 
public enum CampaignStatus : short { 
    Active, 
    Inactive, 
    Todo, 
    Hidden 
} 
public class SqlCampaignRepository : ICampaignRepository 
{ 
... 
    public IQueryable<Campaign> Campaigns() 
    { 
     DataContext db = new DataContext(); 
     return from c in db.Campaigns 
       select new Campaign 
        { 
         Id = c.Id, 
         Name = c.Name, 
         ... 
         Status = (CampaignStatus)c.Status, 
         ... 
        }; 
    } 
} 

Et puis ailleurs

SqlCampaignRepository rep = new SqlCampaignRepository(); 
var query = rep.Campaigns().OrderBy(c => c.Status); 

Cela déclenche l'exception suivante: System.ArgumentException était non gérée par le code utilisateur Message = "L'argument ' valeur 'était le mauvais type.' IQMedia.Models.CampaignType 'attendu.' System.Int16 '. Source = "System.Data.Linq" StackTrace: System.Data.Linq.SqlClient.SqlOrderExpression.set_Expression (valeur SqlExpression) cb System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect cb (SqlSelect select) ved System.Data.Linq.SqlClient.SqlVisitor.Visit (nœud de SqlNode) System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitIncludeScope ved (champ d'application de SqlIncludeScope)

...

(désolé danoise là-dedans , ved = par/at).

J'ai essayé de typer le statut à court dans l'expression orderBy, mais cela ne l'aide pas, même si je l'ai casté au type enum réel aussi bien.

Toute aide pour résoudre ce problème est grandement appréciée!

Répondre

3

Pouvez-vous spécifier le type CampaignStatus directement dans votre DataContext par le concepteur? De cette façon, la valeur est automatiquement mappée au enum.

1

Quelle est la relation entre la classe Campaign et Campaigns? Si Campaigns renvoie l'ensemble de l'objet Campaign, notez que vous ne pouvez normalement pas select new une entité mappée.

Je me demande si cela fonctionnerait mieux si vous avez fait le OrderBy avant le Select?

Une dernière astuce pourrait être de créer un faux composable [Function], en utilisant trivial TSQL. Par exemple, ABS peut être suffisant. à-dire quelque chose comme (le contexte):

[Function(Name="ABS", IsComposable=true)] 
    public int Abs(int value) 
    { // to prove not used by our C# code... 
     throw new NotImplementedException(); 
    } 

essayer ensuite:

.OrderBy(x => ctx.Abs(x.Status)) 

Je ne l'ai pas testé ci-dessus, mais il peut donner un aller plus loin ... ça marche pour une autre similaire cas, cependant.

vaut le coup ...

0

Mon DataContext a sa propre classe d'entité nommée Campagne, (vivant dans un autre espace de noms, bien sûr). La colonne d'état est également enregistrée en tant que smallint dans la base de données et l'espace de noms de l'entité LINQ a son type répertorié en tant que short (System.Int16).

Le orderby fonctionne si je l'applique dans la requête de mon référentiel - tout cela fait partie d'une plus grande chose, et l'idée est de ne PAS appliquer de dépôt, filtrage ou quoi que ce soit, mais il suffit de mapper les classes d'entités de la base de données à mes propres classes. Cet exemple là-bas est évidemment un peu inutile dans lequel il s'agit d'un mappage plutôt droit, mais dans certains cas, j'ai également ajouté une localisation.

Aussi j'ai oublié d'ajouter - l'exception ne se produit évidemment pas jusqu'à ce que j'essaie d'exécuter la requête (ie - appeler ToList, ou énumérer sur la collection).

Dans l'ensemble, cette méthode est utilisée par une classe de service qui est alors supposée ajouter le filtrage, le tri et tout cela - et le but de tout cela est bien sûr de séparer les choses, mais aussi de permettre transition facile vers une base de données différente, ou un OR/M différent, plus tard, si ce serait le désir. Ah, je n'ai pas vu ce dernier bout avant d'avoir répondu - je n'ai pas encore utilisé l'attribut Fonction, mais je n'aurai pas accès au datacontext dans la classe où je suis censé appliquer le tri.