我有一个包含ICollection
:的对象
public abstract class Container : Component, IContainer
{
public virtual ICollection<Component> Components { get; set; }
...
...
}
由于它是虚拟的,Component
s将延迟加载(当"获取"Component
s属性时:myContainerInstance.Components
)。
我们的应用程序在很大程度上依赖于反思。反射部分之一是检索某个Container的所有属性,在其中循环并检索每个属性的值。类似这样的东西:
var props = type.GetProps();
foreach (var prop in props)
{
var propValue = prop.GetValue(bo, null); // EF triggers lazy loading in case the prop is a virtual ICollection and immediately _materializes_ all the data
...
...
}
我正试图找到一种方法,让EF按照指定的顺序检索数据。这有可能吗?我试图在谷歌上搜索是否可以用一个属性来装饰集合属性,该属性将指示EF对其检索日期进行排序。或者我太累了,找不到好的谷歌查询,或者这不可能,或者。。。?
PS:禁用该属性的延迟加载不是一个选项,因为该集合中的某些Component
本身就是Container
。这导致了大量的select语句。理论上,整个对象结构可以包含无限深度(目前实际为4)
据我所知,这是不可能的。
在ObjectContext API中,可以通过从导航属性创建查询来显式加载,但必须关闭延迟加载,因为一旦启用延迟加载,对集合属性的任何访问都会立即触发加载,因此显式加载将再次加载数据。即使开启了延迟加载,DbContext API也应该能够使用显式加载。仍然显式加载意味着必须手动调用某些方法/查询才能加载属性。
以下是我最后所做的(简化版):
var propValue = prop.GetValue(bo, null); // this (in case the `prop` is a virtual `ICollection<Component>`) lazy loads all components, returning them not always in the same order (due to paralelism on sql server?))
if (prop.PropertyType.IsGenericType)
{
...
if (prop.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
...
}
else if (innerType.IsSubclassOfOrEquivalentTo(typeof(Component)) && propValue != null)
{
// order the list of components in memory into a new variable
var listOfComponents = ((IEnumerable) propValue).Cast<Component>().OrderBy(c => c.ComponentId);
dynamic componentsHash = propValue; // I had to use dynamic, because sometimes the propValue was an List<...>, sometimes a HashSet<...>, sometimes a ...
componentsHash.Clear(); // empty the collection retrieved by EF
int componentCount = listOfComponents.Count;
for (var i = 0; i < componentCount; i++)
{
var component = listOfComponents[i];
componentsHash.Add(component); // re-add components to the collection
...
}
// at this point the collection object contains ordered dynamic proxy objects (attached EF objects)
}
else
{
...
}
}
...