Qui de requête LINQ pour sélectionner les lignes à partir de 1 table qui ne sont pas dans une autre table
Je suis du développement d'une application dans laquelle j'ai 2 entités différentes, des Produits et des ShoppingCarts. Chaque produit est unique et possède un identifiant unique. Je veux ajouter un produit qui n'est pas déjà dans un autre panier et qui n'est pas vendu à un ShoppingCart.
Entité de produit simplifié:
public class Products
{
public int Id { get; set; }
public string Name{ get; set; }
public bool Sold { get; set; }
}
Panier entité simplifiée:
public class ShoppingCarts
{
public int Guid Guid { get; set; }
public int ProductId { get; set; }
}
Alors d'abord j'ai récupérer tout le Produit.Id puis-je les ajouter à mon panier. Ma méthode ressemble à ceci:
private IQueryable<Products> GetAvailableProductId(int quantity)
{
var query = (from p in _context.Set<Products>()
join sc in _context.Set<ShoppingCarts>() on p.Id equals sc.ProductId into subset
from sc in subset.DefaultIfEmpty()
where !p.Sold && sc == null
select p).Take(quantity);
return query;
}
Pour une raison quelconque, chaque fois dans un certain temps, les 2 entités avec la même ProductId sont ajoutés à différents chariots. Ce fut l'activation de l'application à vendre 2 des mêmes produits. J'ai fini par la fixation d'effectuer une autre vérification de l'application avant de me faire la transaction.
J'ai revisité le code récemment et suis tombé sur ces postes Requête LINQ: Déterminer si l'objet dans une liste dans une autre basée sur la touche
LINQ to Entité, le rejoindre sur PAS DANS les tableaux
Ma question est de savoir si la modification de ma requête à quelque chose comme ceci permettra d'éviter la double addition.
private IQueryable<Products> NewGetAvailableProductId(int quantity)
{
var query = (from p in _context.Set<Products>()
where !_context.Set<ShoppingCarts>().Any(x => x.ProductId == p.Id) && !p.Sold
select p).Take(quantity);
return query;
}
Si il y a des doutes, s'il vous plaît laissez-moi savoir si je peut l'expliquer mieux.
Merci,
OriginalL'auteur lopezbertoni | 2012-07-11
Vous devez vous connecter pour publier un commentaire.
Obtenir les différents dossiers de votre requête initiale devrait vous obtenir le résultat souhaité. Remarque la nette() avant de les Prendre().
La raison vous avez des doublons, c'est que la requête originale vous donnera une liste des correspond entre la table produit et le panier de la table. par exemple, si vous avez
product1
danscart1
etcart2
et unproduct2
dans aucun des charrettes, vous obtiendrez les résultats suivants de la rejoindre.vous puis filtrer le null chariots
vous sélectionnez uniquement le produit objet
À ce stade, vous êtes de gauche avec les produits dupliqués. La fonction distincte j'ai ajouté ensuite prendre cette liste et supprimer toutes les entrées en double. vous laissant avec,
Il est intéressant de vérifier le sql généré par chacune des requêtes comme ils peuvent être assez différentes, même si elles produisent des résultats similaires. Je suppose que votre première requête va utiliser une JOINTURE EXTERNE GAUCHE tandis que la seconde va utiliser une clause IN. Je voudrais utiliser la JOINTURE EXTERNE GAUCHE que dans mon expérience DANS de telles clauses sont assez lent, et doit être évitée si possible. Évidemment, vous devriez mesurer ce dans votre propre environnement.
Aussi, votre deuxième question est absent de la
where !p.Sold
qui était dans la première.Par ailleurs, vous avez raison à propos de favoriser la Jointure Externe Gauche sur la clause in.
J'ai ajouté une explication sur pourquoi vous obtenez parfois des doublons et comment répondre à cette aide. Je suis d'accord que GalacticCowboy la réponse est la meilleure façon de résoudre votre problème en particulier, mais j'espère que ma réponse vous donne un aperçu de la façon dont linq œuvres
Il ne m'a donné plus de perspicacité, merci. Mon problème a fini par être que j'ai d'abord requête de produits disponibles, puis, dans une étape distincte, les insérer dans des chariots la table un par un. La solution que j'ai trouvé est de ne pas utiliser LINQ, l'utilisation d'un INSERT avec une instruction SELECT en SQL. Merci pour les commentaires.
OriginalL'auteur Dave Turvey
J'ai un sentiment que vous êtes involontairement aboiements le mauvais arbre.
Voici le résumé du scénario:
Fondamentalement, vous avez besoin d'une opération, de la section critique, singleton, ou à un appareil pour vous assurer qu'une et une seule personne peut vérifier et ajouter à leur panier comme une seule opération, il doit réussir ou échouer en tant qu'une seule unité de travail.
Oui, il pourrait l'aider, parce que vous risquez d'annuler la transaction si il y avait un conflit. Il y a d'autres la synchronisation des idées - comme l'appel d'une proc de votre contexte EF - qui fonctionne aussi bien ou mieux.
OriginalL'auteur GalacticCowboy
S'il vous plaît vérifier à cette question: LINQ to Entité, le rejoindre sur PAS DANS les tableaux. Beaucoup plus propre approche que les solutions ci-dessus.
À la recherche à votre requête, il n'y a rien à garder répété des dossiers de présentation. Vous avez besoin d'utiliser cette: Comment puis-je utiliser Linq pour obtenir une liste unique de propriétés à partir d'une liste d'objets?
OriginalL'auteur aldosa