代码之家  ›  专栏  ›  技术社区  ›  Chris Charabaruk

在实体框架中构建堆栈

  •  1
  • Chris Charabaruk  · 技术社区  · 17 年前

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

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

    E1实体: {堆栈: 库克斯 , 插头 , glurp }, {堆栈: 插头 glurp 巴兹 {堆栈: 库克斯 插头 }

    {顶部: null ; 在: , 巴兹 }, 巴兹 ; 在: , 酒吧 , glurp 酒吧 ; 在: , 酒吧 }

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

    2 回复  |  直到 17 年前
        1
  •  1
  •   Daniel Brückner    17 年前

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

    现在,假设联接表名为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。

    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();
       }
    }
    

    用如下内容扩展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);
          }
       }
    }
    

    你就这样结束了。现在应该可以围绕这些实体编写非常好的代码了。可能代码中有一些bug,但是想法应该很清楚。我省略了代码,以确保在访问时加载相关属性。您可以进一步将原始属性私有化,并将其隐藏在外部。也许您不应该包括NiceStack属性,因为它允许随机访问。或者,您可能希望添加更多扩展—可能使NiceTop可写—将E2实例推送到插入E2实例NiceTop的E1实例的堆栈上。但想法仍然是一样的。

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

        2
  •  1
  •   MarkusQ    17 年前

    • 对吗?
    • 将Rs链接起来(给他们一个“下一个指针”而不是“位置”)有意义吗
    • E2真的需要知道他们不在顶端的情况吗?