1

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

这对我来说听起来并不那么清楚,所以让我尝试演示一下:

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

E2 实体:quux { top: null; 在:foobaz },plugh { 顶部:baz;在:foobarbaz },glurp { 顶部:bar;在:foobar }

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

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

4

2 回答 2

1

因此,如果我们将您的关系表称为 R,则每个 E1“包含”多个 R(它是堆栈,按 R.position 排序)并且每个 E2 以两种方式包含多个 R:具有 R.position == R.e1.top 的那些和那些这不成立)。

  • 那是对的吗?
  • 您如何跟踪顶部?当堆栈更改时(例如,e1.top 是恒定的),您是更新 E1 的所有 Rs,还是将其存储在每个 E1 中?
  • 将 Rs 链接起来是否有意义(给他们一个“下一个指针”而不是一个“位置”)
  • 你需要随机访问堆栈吗?
  • E2 真的需要了解他们不在顶部的情况吗?
于 2009-03-18T18:07:28.673 回答
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; }
}

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

使用以下内容扩展 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() 的调用不适用于普通的实体框架;而是使用 ToList().Single() 切换到 LINQ to Object 或使用 First() 但 first() 不保留确切的语义。

于 2009-03-18T18:48:34.953 回答