1 votes

Construire une pile dans Entity Framework

Un type d'entité dans mon modèle (appelons-le E1) doit pouvoir traiter sa relation avec un autre type d'entité (E2) comme une pile. Réciproquement, l'autre entité doit pouvoir voir toutes les entités liées du premier type où E2 est en haut de la pile, et séparément chaque cas où E2 est au sein d'une pile pour un E1.

Cela ne me semble pas très clair, alors laissez-moi essayer de démontrer :

Entités E1 : foo { pile : quux, plugh, glurp }, bar { pile : plugh, glurp }, baz { pile : quux, plugh }

Entités E2 : quux { haut : null; dans : foo, baz }, plugh { haut : baz; dans : foo, bar, baz }, glurp { haut : bar; dans : foo, bar }

Actuellement, j'ai une table de base de données qui a des colonnes pour les clés à la fois de E1 et E2, ainsi qu'un entier pour stocker la position de E2 dans la pile. Entity Framework traite cette table comme son entité propre, plutôt que comme faisant partie de la relation entre E1 et E2, ce qui complique les requêtes et entraîne simplement un code assez laid.

Je sais que je fais mal, mais est-il possible de faire correctement ? Et si oui, comment ?

1voto

MarkusQ Points 15612

Donc si nous appelons votre table de relation R, chaque E1 "contient" plusieurs Rs (sa pile, ordonnée par R.position) et chaque E2 contient plusieurs Rs de deux manières : ceux avec R.position == R.e1.top et ceux où cela n'est pas vrai).

  • Est-ce correct ?
  • Comment suivez-vous le haut ? Mettez-vous à jour tous les Rs pour un E1 lorsque la pile change (par exemple, e1.top est constant) ou le stockez-vous dans chaque E1 ?
  • Aurait-il du sens d'avoir les Rs enchaînés (leur donnant un "pointeur suivant" plutôt qu'une "position")
  • Avez-vous besoin d'un accès aléatoire aux piles ?
  • Est-ce que les E2 ont vraiment besoin de savoir dans les cas où ils ne sont pas en haut ?

1voto

Daniel Brückner Points 36242

Parce que c'est une situation assez exotique, il n'y a pas de support intégré pour cela. Mais vous pouvez le rendre joli.

Pour l'instant, vous avez quelque chose comme ça en supposant que votre table de jointure s'appelle E1E2.

public partial class E1
{
   public Guid Id { get; set; }
   public IQueryable Stack { get; }
}

public partial class E2
{
   public Guid Id { get; set; }
   public IQueryable In { get; }
}

public partial class E1E2
{
   public E1 E1 { get; set; }
   public E2 E2 { get; set; }
   public Int32 Position { get; set; }
}

À l'heure actuelle, je ne peux pas trouver de meilleure solution pour mapper cela dans une base de données. Pour rendre l'utilisation aussi intelligente que possible, ajoutez simplement des propriétés et des méthodes aux entités. C'est facile car les entités sont générées comme des classes partielles.

Étendez la classe E1 comme suit.

public partial class E1
{
   public IQueryable NiceStack
   {
      get { return this.Stack.Select(s => s.E2).OrderBy(s => s.Position); }
   }

   public void Push(E2 e2)
   {
      this.Stack.Add(
         new E1E2
         {
            E2 = e2,
            Position = this.Stack.Max(s => s.Position) + 1
         });
   }

   public E2 Pop()
   {
      return this.Stack.
         Where(s => s.Position == this.Stack.Max(s => s.Position)).
         Select(s => s.E2).
         Single();
   }
}

Étendez la classe E2 comme suit.

public partial class E2
{
   public IQueryable NiceIn
   {
      get { return this.In.Select(i => i.E1); }
   }

   public IQueryable NiceTop
   {
      get
      {
         return this.In.
            Where(i => i.Position == i.E1.Stack.Max(s => s.Position)).
            Select(i => i.E1);
      }
   }
}

Et voilà. Maintenant, il devrait être possible d'écrire un code assez propre autour de ces entités. Il y a probablement des bogues dans le code mais l'idée devrait être claire. J'ai laissé de côté le code pour garantir que les propriétés liées sont chargées lors de leur accès. Vous pourriez rendre les propriétés originales privées et les masquer de l'extérieur. Peut-être ne devriez-vous pas inclure la propriété NiceStack car cela permet un accès aléatoire. Ou peut-être voulez-vous ajouter plus d'extensions - peut-être rendre NiceTop inscriptible en poussant une instance de E2 sur la pile d'une instance de E1 insérée dans NiceTop de l'instance de E2. Mais l'idée reste la même.

L'appel à Single() ne fonctionnera pas avec l'Entity Framework normal; utilisez plutôt ToList().Single() pour passer à LINQ to Object ou utilisez First() mais First ne préserve pas la sémantique de un seul élément.

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