Sort Collection by decorating a property with an attribute. (collection retrieval is triggered through reflection)
I have an object which contains an ICollection
:
public abstract class Container : Component, IContainer
{
public virtual ICollection<Component> Components { get; set; }
...
...
}
Since it is virtual, the Component
s will be lazy loaded (when 'getting' the Component
s property: myContainerInstance.Components
).
Our application is heavily relying on reflection. One of the reflection parts is retrieving all properties of a certain Container, loops through开发者_StackOverflow中文版 it and retrieves the value of each property. Something like this:
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
...
...
}
I am trying to find a way how to have EF retrieve that data with an order by specified. Is that somehow possible? I was trying to google if maybe it's possible to decorate that collection property with an attribute that would instruct EF to order the date its retrieving. Or I'm too tired to find the good google query, or it's not possible, or ...?
PS: disabling lazy loading for that property is not an option, since certain Component
s in that collection are Container
s on its own. This causes humongous select statements. The whole object structure can theoretically contain an infinite depth (reality is - for now - up to 4)
As I know it is not possible.
In ObjectContext API it is possible with explicit loading by creating query from navigation property but lazy loading must be turned off because once lazy loading is enabled any access to collection property immediately triggers loading so the explicit loading will load data again. DbContext API should be able to use explicit loading even if lazy loading is turned on. Still explicit loading means that you must call some method / query manually to load the property.
Here's what I did in the end (simplified version):
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
{
...
}
}
...
精彩评论