Entity framework 在实体框架中构建堆栈

Entity framework 在实体框架中构建堆栈,entity-framework,stack,Entity Framework,Stack,我模型中的一种实体类型(我们称之为E1)需要能够将其与另一种实体类型(E2)的关系视为堆栈。反过来,该另一实体需要能够看到E2位于堆栈顶部的第一种类型的所有相关实体,以及E2位于E1堆栈内的每种情况 我觉得这听起来不太清楚,所以让我试着证明: E1实体:foo{stack:quox,plugh,glurp},bar{stack:plugh,glurp},baz{stack:quox,plugh} E2实体:quux{top:null;in:foo,baz},plugh{top:baz;in:fo

我模型中的一种实体类型(我们称之为E1)需要能够将其与另一种实体类型(E2)的关系视为堆栈。反过来,该另一实体需要能够看到E2位于堆栈顶部的第一种类型的所有相关实体,以及E2位于E1堆栈内的每种情况

我觉得这听起来不太清楚,所以让我试着证明:

E1实体:foo{stack:quox,plugh,glurp},bar{stack:plugh,glurp},baz{stack:quox,plugh}

E2实体:quux{top:
null
;in:foo,baz},plugh{top:baz;in:foo,baz},glurp{top:bar;in:foo,bar}

现在,我有一个数据库表,其中包含E1和E2键的列,以及用于存储E2在堆栈中位置的int。实体框架将此表视为其自己的实体,而不是E1和E2之间关系的一部分,这会使查询复杂化,并导致一些非常难看的代码


我知道我做错了,但有可能做对吗?如果是这样,怎么做?

因此,如果我们调用关系表R,每个E1“包含”多个R(它是堆栈,按R.position排序),每个E2以两种方式包含多个R:R.position==R.E1.top的和不包含的)

  • 对吗
  • 你是如何追踪最高层的?当堆栈发生变化时(例如E1.top为常数),您是否更新E1的所有Rs,还是将其存储在每个E1中
  • 将Rs链接起来(给他们一个“下一个指针”而不是“位置”)有意义吗
  • 您需要随机访问堆栈吗
  • E2真的需要知道他们不在顶端的情况吗

    • 因为这是一种非常奇特的情况,所以没有内置支持。但是你可以让它看起来很漂亮

      现在,假设联接表名为E1E2,则会出现类似的情况

      public partial class E1
      {
         public Guid Id { get; set; }
         public IQueryable<E1E2> Stack { get; }
      }
      
      public partial class E2
      {
         public Guid Id { get; set; }
         public IQueryable<E1E2> In { get; }
      }
      
      public partial class E1E2
      {
         public E1 E1 { get; set; }
         public E2 E2 { get; set; }
         public Int32 Position { get; set; }
      }
      
      公共部分类E1
      {
      公共Guid Id{get;set;}
      公共IQueryable堆栈{get;}
      }
      公共部分类E2
      {
      公共Guid Id{get;set;}
      {get;}中的公共IQueryable
      }
      公共部分类E1E2
      {
      公共e1e1{get;set;}
      公共E2 E2{get;set;}
      公共Int32位置{get;set;}
      }
      
      作为hoc,我无法想出更好的解决方案来将其映射到数据库。要使使用尽可能智能,只需向实体添加一些属性和方法。这很容易,因为实体a是作为分部类生成的

      用如下内容扩展类E1

      public partial class E1
      {
         public IQueryable<E2> 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();
         }
      }
      
      公共部分类E1
      {
      公共IQueryable堆栈
      {
      获取{返回this.Stack.Select(s=>s.E2).OrderBy(s=>s.Position);}
      }
      公共无效推送(E2)
      {
      这个是.Stack.Add(
      新E1E2
      {
      E2=E2,
      Position=this.Stack.Max(s=>s.Position)+1
      });
      }
      公共服务
      {
      返回这个.Stack。
      其中(s=>s.Position==this.Stack.Max(s=>s.Position)。
      选择(s=>s.E2)。
      单个();
      }
      }
      
      用如下内容扩展E2类

      public partial class E2
      {
         public IQueryable<E1> NiceIn
         {
            get { return this.In.Select(i => i.E1); }
         }
      
         public IQueryable<E1> NiceTop
         {
            get
            {
               return this.In.
                  Where(i => i.Position == i.E1.Stack.Max(s => s.Position)).
                  Select(i => i.E1);
            }
         }
      }
      
      公共部分类E2
      {
      公共可查询信息
      {
      获取{返回this.In.Select(i=>i.E1);}
      }
      公共IQueryable NiceTop
      {
      得到
      {
      把这个还给我。
      其中(i=>i.Position==i.E1.Stack.Max(s=>s.Position))。
      选择(i=>i.E1);
      }
      }
      }
      
      到此为止。现在应该可以围绕这些实体编写非常好的代码了。代码中可能有一些bug,但想法应该很清楚。我省略了代码,以确保在访问时加载相关属性。您可以进一步将原始属性设为privat并从外部隐藏。也许您应该这样做不包括NiceStack属性,因为这允许随机访问。或者,您可能希望添加更多扩展-可能使NiceTop可写,将E2实例推送到插入E2实例NiceTop的E1实例的堆栈上。但想法保持不变


      对Single()的调用将不适用于普通实体框架;而是使用ToList().Single()切换到LINQ to Object或使用First()但首先并不能保留一个的语义。

      现在每个E2只以一种方式包含多个R,并且通过LINQ查询确定top。我希望R完全不可见,E1s在关系的末尾有一个堆栈对象,E2s有两个列表——一个用于top,一个用于一般堆栈内。随机a只要知道E2在E1的堆栈中的某个位置,就只需要访问,这样,如果E2想要更改堆栈上的内容,它就可以这样做。(E2将E1委托给他们,并且可以将这些E1委托给其他E2,包括更改他们之前将E1委托给的人。)链接(我的理解是给每个R一个可为空的列来指向另一个R)可能也很好,但我担心可能会进一步增加问题的复杂性。OTOH更难搞错,这意味着我不再有拆分键了。(R的PK是(E1.键,位置)atm。)