ADO.NET 实体框架分层数据
考虑以下数据库模型:
和以下查询代码:
using (var context = new DatabaseEntities())
{
return context.Feed.ToHierarchy(f => f.Id_Parent, null);
}
其中 ToHierarchy
是ObjectSet
as:
public static List<TEntity> ToHierarchy<TEntity, TProperty>(this ObjectSet<TEntity> set, Func<TEntity, TProperty> parentIdProperty, TProperty idRoot) where TEntity : class
{
return set.ToList().Where(f => parentIdProperty(f).Equals(idRoot)).ToList();
}
这将导致示例 JSON 格式的响应:
[
{
"Description":"...",
"Details":[ ],
"Id":1,
"Id_Parent":null,
"Title":"...",
"URL":"..."
},
{
"Description":"...",
"Details":[
{
"Description":"...",
"Details":[ ],
"Id":4,
"Id_Parent":3,
"Title":"...",
"URL":"..."
},
{
"Description":"...",
"Details":[
{
"Description":"...",
"Details":[
{
"Description":"...",
"Details":[ ],
"Id":7,
"Id_Parent":6,
"Title":"...",
"URL":"..."
}
],
"Id":6,
"Id_Parent":5,
"Title":"...",
"URL":"..."
}
],
"Id":5,
"Id_Parent":3,
"Title":"...",
"URL":null
}
],
"Id":3,
"Id_Parent":null,
"Title":"...",
"URL":null
}
]
正如您可能已经注意到 ToHierarchy
方法应该(并且显然确实)从 a 中检索所有行给定集合(平面)并根据“父属性”返回这些的分层表示。
当我在实施过程中时,我快速尝试了我的代码,令人惊讶的是它有效!现在,我想象这对你们许多人来说听起来有多奇怪,但我真的不明白这段代码为什么或如何工作,即使我自己把它写下来......
你能解释一下它是如何工作的吗?
PS:如果你仔细观察,ToHierarchy
与 .Include("Details")
并不相同。
Consider following database model:
And following query code:
using (var context = new DatabaseEntities())
{
return context.Feed.ToHierarchy(f => f.Id_Parent, null);
}
Where ToHierarchy
is an extension to ObjectSet<TEntity>
as:
public static List<TEntity> ToHierarchy<TEntity, TProperty>(this ObjectSet<TEntity> set, Func<TEntity, TProperty> parentIdProperty, TProperty idRoot) where TEntity : class
{
return set.ToList().Where(f => parentIdProperty(f).Equals(idRoot)).ToList();
}
This would result in example JSON formatted response:
[
{
"Description":"...",
"Details":[ ],
"Id":1,
"Id_Parent":null,
"Title":"...",
"URL":"..."
},
{
"Description":"...",
"Details":[
{
"Description":"...",
"Details":[ ],
"Id":4,
"Id_Parent":3,
"Title":"...",
"URL":"..."
},
{
"Description":"...",
"Details":[
{
"Description":"...",
"Details":[
{
"Description":"...",
"Details":[ ],
"Id":7,
"Id_Parent":6,
"Title":"...",
"URL":"..."
}
],
"Id":6,
"Id_Parent":5,
"Title":"...",
"URL":"..."
}
],
"Id":5,
"Id_Parent":3,
"Title":"...",
"URL":null
}
],
"Id":3,
"Id_Parent":null,
"Title":"...",
"URL":null
}
]
As you may have noticed ToHierarchy
method is supposed to (and apparently do indeed) retrieve all rows from a given set (flat) and return hierarchical representation of these as per "parent property".
When I was in the middle of my implementation I quick tried my code and surprisingly it worked! Now, I imagine how weird does this sound to many of you, but I really don't understand why or how that piece of code works, even though I kinda wrote it down on my own...
Could you explain how does it work?
P.S.: if you look closer, ToHierarchy
is not near the same as .Include("Details")
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
它之所以有效,是因为
set.ToList
会将数据库表中的所有记录加载到您的应用程序,其余的工作由 EF 及其更改跟踪机制完成,该机制应确保相关实体之间的正确引用。顺便提一句。您正在过滤应用程序内存中的记录,而不是数据库中的记录。例如,如果您的表包含 10000 条记录,而您的过滤器应仅返回 10 条,您仍将从数据库加载所有 10000 条记录。
您会发现使用 EF 实现这一点非常困难,因为 EF 不支持分层数据。你总是会以糟糕的解决方案结束。唯一好的解决方案是使用存储过程和对数据库中分层查询的一些支持 - 例如 SQL Server 中的公用表表达式 (CTE)。
我刚刚做了这个非常简单的示例,它的工作原理正如我在评论中所描述的那样:
它使用代码优先方法,但在内部它与使用 EDMX 时相同。当我获取
data
时,列表中有 5 个实体,并且所有实体都已正确配置Parent
和Children
导航属性。It works because
set.ToList
will load all records from the database table to your application and the rest is done be EF and its change tracking mechanism which should ensure correct referencing between related entities.Btw. you are filtering records in the memory of your application, not in the database. For example if your table contains 10000 records and your filter should return only 10, you will still load all 10000 from the database.
You will find that implementing this with EF is quite hard because EF has no support for hierarchical data. You will always end with bad solution. The only good solution is using stored procedure and some support for hierarchical queries in the database - for example common table expressions (CTE) in SQL server.
I just made this very simple example and it works as I described in comment:
It uses code first approach but internally it is same as when using EDMX. When I get
data
I have 5 entities in list and all have correctly configuredParent
andChildren
navigation properties.