我模型中的一种实体(我们称之为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之间关系的一部分,这会使查询复杂化,只会导致一些简单的丑陋代码。
我知道我做错了,但有可能做到这一点吗?如果是这样,怎么样?
答案 0 :(得分:1)
因此,如果我们调用你的关系表R,每个E1“包含”多个R(它的堆栈,按R.position排序),每个E2包含两个方式的多个Rs:具有R.position == R.e1的那些。顶部和那些不成立的地方。
答案 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()但首先不保留恰好一个的语义。