在Entity Framework中构建堆栈

时间:2009-03-18 17:51:38

标签: entity-framework stack

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

这听起来并不是那么清楚,所以让我试着说明一下:

E1实体: foo {stack: quux plugh glurp }, bar < / strong> {stack: plugh glurp }, baz {stack: quux plugh < / em>}

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

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

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

2 个答案:

答案 0 :(得分:1)

因此,如果我们调用你的关系表R,每个E1“包含”多个R(它的堆栈,按R.position排序),每个E2包含两个方式的多个Rs:具有R.position == R.e1的那些。顶部和那些不成立的地方。

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

答案 1 :(得分:1)

因为这是一个非常奇特的情况,所以没有建立支持。但你可以让它看起来不错。

现在你有类似的东西,假设你的连接表叫做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; }
}

As hoc我无法想出一个更好的解决方案来将其映射到数据库。为了使用尽可能智能,只需向实体添加一些属性和方法。这很容易,因为它会产生一个部分类。

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

到此为止。现在应该可以围绕这个实体编写相当不错的代码。可能代码中存在一些错误,但这个想法应该是明确的。我省略了代码以确保在访问时加载相关属性。您可以进一步将原始属性设为私有,并将其隐藏在外部。也许您不应该包含NiceStack属性,因为这允许随机访问。或者您可能想要添加更多扩展 - 也许使NiceTop可写将E2实例推入插入E2实例的NiceTop的E1实例的堆栈中。但这个想法仍然是一样的。

对Single()的调用不适用于普通的Entity Framework;而是使用ToList()。Single()切换到LINQ to Object或使用First()但首先不保留恰好一个的语义。