1
votes

Utilisation de LINQ pour remplir une chaîne avec une seule valeur de colonne

Je suis un débutant à la fois en C # et LINQ et j'apprécierais un petit coup de pouce dans la bonne direction.

Premièrement, j'ai une table SQL Overrides (et un contexte EF DB correspondant), qui a un Type, Valeur et valeur de remplacement. L'idée est que pour un type particulier ("Type") de remplacement, le code peut vérifier une valeur particulière et aller voir s'il existe une valeur de remplacement qui devrait être utilisée à la place.

string readingOverride = select OverrideValue from branchOverrides where Value = "Reading"

Dans ce cas, je veux la liste des différentes valeurs de remplacement du type "Branch Override". À partir de là, j'aimerais pouvoir récupérer une valeur de remplacement spécifique à un point donné de mon code. Comment puis-je interroger la variable branchOverrides que j'ai créée pour pouvoir dire quelque chose comme:

var branchOverrides = overridesSqlContext.Overrides
  .Where(q => q.Type == "Branch Override")
  .Select(s => new
    {
      s.Value,
      s.OverrideValue
    });

Mon code devra être capable de lire diverses valeurs de remplacement pour différentes branches à différents points, et pouvoir interroger la variable branchOverrides à tout moment semblerait être l'approche idéale.

Merci pour toute aide à ce sujet.


0 commentaires

4 Réponses :


2
votes

Vous pouvez utiliser Single () sur l'objet de requête que vous avez:

string readingOverride = branchOverrides
    .Single(bo => bo.Value == "Reading")
    .OverrideValue;

Cela lèvera une exception si une entrée n'existe pas, donc vous souhaitez utiliser SingleOrDefault à la place et rechercher un retour nul.

Notez également que l'objet branchOverrides ici est un IQueryable code> ce qui signifie qu'à chaque fois que vous l'utiliserez, il enverra une requête à la base de données. Vous voudrez peut-être matérialiser cela dans une liste locale en ajoutant .ToList () après Select (...) . Vous pouvez également envisager de mettre en cache ces données, surtout si elles vont être utilisées fréquemment.


4 commentaires

Pourquoi utiliseriez-vous .Single () sur .First () ? Pensez-vous qu'il pourrait y en avoir plus d'un?


@nvoigt Cela n'a pas de sens d'avoir plusieurs remplacements pour le même type. Si plusieurs sont autorisés, lequel doit être choisi? Soit il doit y avoir un moyen de choisir l'une des nombreuses valeurs qu'ils veulent, soit il ne devrait jamais y en avoir qu'une, donc Single serait correct. Pourquoi pensez-vous qu'il serait approprié de choisir simplement une valeur de remplacement aléatoire parmi les nombreuses valeurs possibles?


@Servy Parce que si cela est une requête de base de données, cela aura un impact sur les performances de vérifier cette condition à chaque lecture au lieu d'une fois lors de l'insertion.


@nvoigt Bien qu'il y ait une surcharge dans la DB d'appeler Single (car il prend 2 valeurs et lance si plus de 1 retourne), je ne pense pas que ce soit extrêmement pertinent ici. Si les performances étaient un problème, peut-être que ces valeurs sont nécessaires partout et sont fréquemment consultées, alors vous feriez bien mieux de mettre les données en cache localement.



0
votes

Si Value est unique dans "Branch Override", vous voudrez peut-être le transformer en dictionnaire pour une recherche rapide

var readingOverride = branchOverrides["Reading"];

Ensuite, vous pourrez trouver le remplacement valoriser rapidement et efficacement

var branchOverrides = overridesSqlContext.Overrides
        .Where(q => q.Type == "Branch Override")
        .Select(s => new
        {
            s.Value,
            s.OverrideValue
        })
        .ToDictionary(k => k.Value, v => v.OverrideValue);


9 commentaires

Pourquoi voudriez-vous copier toutes les données dans une liste, seulement pour jeter immédiatement cette liste et ne jamais l'utiliser pour quoi que ce soit?


@Servy TBH Je n'étais pas sûr que ToDictionary se traduirait en SQL alors j'ai simplement matérialisé la liste.


Il n'y a pas de méthode Queryable.ToDictionary , donc il ne pouvait pas le traduire en SQL même si le fournisseur de requêtes voulait essayer. Et si vous voulez vous assurer qu'une méthode utilise une surcharge IEnumerable plutôt qu'une surcharge IQueryable , il n'est pas nécessaire de copier l'ensemble de résultats dans une liste et de jeter la liste à accomplir cela.


@Servy vous avez raison. J'étais juste paresseux. Mise à jour


AsEnumerable est moins dangereux, mais tout aussi inutile. Encore une fois, il n'y a pas d'implémentation Queryable de ToDictionary en premier lieu .


@Servy c'est exactement le point. Vous voulez probablement que quelque chose comme ça soit un dictionnaire, mais vous devez matérialiser la liste pour en faire un.


Non, non. Vous n'avez pas du tout besoin de le matérialiser dans une liste. Vous n'avez pas besoin d'appeler aucune méthode dessus pour appeler` ToDictionary , il vous suffit d'appeler ToDictionary` et cela fonctionne aussi efficacement, juste sans la surcharge supplémentaire.


Je pense que ce que dit Servy, c'est que parce que ToDictionary n'est pas défini pour interrogeable, il peut être utilisé exactement de la même manière que ToList est utilisé. La ligne AsEnumerable () ici est donc inutile.


Ok, j'ai pensé que cela essayerait de le convertir en sql.



1
votes

Si j'ai bien compris, vous voulez l'entrée avec Value = "Reading" et Type = "Branch Override":

var branchOverride = overridesSqlContext.Overrides
            .SingleOrdDefault(q => q.Type == "Branch Override"
                                && q.Value == "Reading")
            .Select(s => new
            {
                s.Value,
                s.OverrideValue
            });
if (branchOverride != null)
{
  // do whatever ...
}


0 commentaires

1
votes

Pour des problèmes de performances, il est bon de mettre .ToList () à la fin de votre expression LINQ si vous avez besoin d'itérer sur cette liste trop de fois.

string readingOverride = string.Empty;

var branchOverride = branchOverrides.FirstOrDefault(x => x.Value == "Reading");

if(branchOverride != null)
{
  readingOverride = branchOverride.OverrideValue;
}

Si vous chargez le liste entière dans la mémoire en évitant d'exécuter la requête SQL pour récupérer les données si vous avez besoin d'itérer dans votre liste.

Une autre chose que vous pouvez faire est:

var branchOverrides = overridesSqlContext.Overrides
  .Where(q => q.Type == "Branch Override")
  .Select(s => new
    {
      s.Value,
      s.OverrideValue
    }).ToList();


0 commentaires