3 votes

Utilisation de noms de colonnes dynamiques dans une requête Linq

foreach (Dimension dimensions in Enum.GetValues(typeof(Dimension)))
{
    var r = new ReferenceTable(dimensions).referenceItems;
    List<TVRawDataRecord> qry = TVRawDataList.Where(p => !r.Any(d => d.Value == p.BrandVariant))
                                             .ToList();                
    DimensionItem di = new DimensionItem(qry, dimensions);
    newDimensions.Add(di); 
 }

Je essaie de créer une requête Linq qui compare une liste de TVRawDataRecords avec ceux d'une enum de Dimensions et lorsque qu'il n'y a pas de correspondance, les ajoute à une nouvelle liste de DimensionItem. Tout fonctionne bien, mais j'ai besoin de substituer dynamiquement le p.BrandVariant dans ma déclaration Where avec la valeur de l'enum de dimensions car la valeur de la dimension est la même que le nom de la propriété TVRawDataRecord. Cela me permettrait de n'avoir que ces quelques lignes de code pour parcourir 8 dimensions, etc.

Est-ce que quelqu'un peut m'expliquer comment inclure la dimension dans ma déclaration Where? Merci!

1voto

nawfal Points 13500

Tout d'abord, c'est vraiment une chose bizarre à faire. Vous devriez d'abord penser à un design alternatif. Il y en a quelques uns qui me viennent à l'esprit maintenant.

Quoi qu'il en soit, vous pourriez utiliser la réflexion pour atteindre ce que vous essayez d'atteindre., enfin presque..

foreach (Dimension dimension in Enum.GetValues(typeof(Dimension)))
{
    var r = new ReferenceTable(dimension).referenceItems;
    var qry = TVRawDataList.Where(p => !r.Any(d => IsAMatch(p, dimension, d.Value)))
                           .ToList();     

    DimensionItem di = new DimensionItem(qry, dimension);
    newDimensions.Add(di); 
}

bool IsAMatch(TVRawDataRecord obj, Dimension dimension, T valueToMatch)
{
    return valueToMatch == dimension.MapToTvRecordProperty(obj);
}

T MapToTvRecordProperty(this Dimension dimension, TVRawDataRecord obj)
{
    return obj.GetPropertyValue(dimension.ToString());
}

T GetPropertyValue(this TVRawDataRecord obj, string propertyName)
{
     var property = typeof(TVRawDataRecord).GetProperty(propertyName);
     if (property == null)
         return null; //ou lancer ce que vous voulez

     return (T)property.GetValue(obj, null);
}

Strictement non testé, non compilé. Mais cela devrait donner une idée de comment cela se fait. Vous pouvez rendre la fonction GetPropertyValue plus générique, mais c'est une autre chose. L'argument de type T dans la fonction Map (qui mappe un enum dimension à une propriété de la classe TVRawDataRecord) est passé car vous devez connaître le type de retour de la propriété.

Je dirais qu'une meilleure conception alternative est simplement de créer une fonction simple qui utilise une logique if else pour retourner le bon type. Donc changez la fonction Map à ceci:

T MapToTvRecordProperty(this Dimension dimension, TVRawDataRecord obj)
{
    switch (dimension)
    {
        case Dimension.BrandVariant:
            return obj.BrandVariant;
        case Dimension.Creative:
            return obj.Creative;

        .....

        default:
            throw;
    }
}

L'avantage est que même si, à l'avenir, vous changez le nom de l'une des variables, votre code ne se cassera pas (contrairement à l'approche de réflexion). Mais le problème ici est de choisir le type de retour T. Le deuxième exemple ne compilerait pas car le type de retour ne correspond pas à ce qui est retourné. Si toutes les propriétés sont du même type, vous pouvez choisir ce type. Si c'est vraiment variable, alors vous devrez d'abord caster votre propriété en objet puis en T, mais toujours mieux que la réflexion !!

Une approche encore meilleure serait de spécifier des attributs soit à la propriété ou à l'enum.

Et surtout si BrandVariant et Creative etc sont des classes à part entière, vous pouvez les faire toutes implémenter une interface qui aura une propriété en lecture seule Dimension sur eux et vous pourrez accéder à cette propriété de vos propriétés d'enregistrement tv pour obtenir la bonne valeur de dimension!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X