Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting nested collection in projection: Unable to cast object of type 'SortOp' to type 'ProjectOp'

I'm using projection of query results to a custom type, which isn't a part of entity data model:

public sealed class AlgoVersionCacheItem : NotificationObject
{
    public int OrderId { get; set; }
    public string OrderTitle { get; set; }
    public int? CurrentVersion { get; set; }
    public int CachedVersion { get; set; }
    public IEnumerable<int> AvailableVersions { get; set; }
}

I want AvailableVersions to be sorted in descending order. Hence, I've tried to add sorting for AvailableVersions in projection:

        return someQueryable
            .Select(version => new AlgoVersionCacheItem
            {
                OrderId = version.OrderId,
                OrderTitle = version.Order.Title,
                CurrentVersion = version.Order.CurrentAlgoVersionId,
                CachedVersion = version.Id,
                AvailableVersions = version
                    .Order
                    .AlgoVersions
                    .Where(v => (allowUncommittedVersions || v.Statuses.Any(s => s.AlgoVersionStatusListItemId == ModelConstants.AlgoVersionCommitted_StatusId)) && v.Id != version.Id)
                    .OrderByDescending(v => v.Id) // this line will cause exception
                    .Select(v => v.Id)
            })
            .Where(item => item.AvailableVersions.Any())
            .OrderByDescending(item => item.OrderId)
            .ToArray();

With sorting, execution of the query throws an System.Data.EntityCommandCompilationException with System.InvalidCastException as inner exception:

Unable to cast object of type 'System.Data.Entity.Core.Query.InternalTrees.SortOp' to type 'System.Data.Entity.Core.Query.InternalTrees.ProjectOp'

Without .OrderByDescending(v => v.Id) everything works fine.
Is this yet another feature, that isn't supported in Entity Framework, or I've missed something?

P.S. I know, that I can sort items later at client side, but I'm wondering about sorting at the server side.

like image 254
Dennis Avatar asked Oct 18 '13 07:10

Dennis


1 Answers

This is a bug in EF. I was able to repro this on both EF5 and EF6. I think you should be able to workaround the bug by filtering records before creating the results i.e.:

return someQueryable
    .Where(version => version.Order.AlgoVersions.Any(v => (allowUncommittedVersions || v.Statuses.Any(s => s.AlgoVersionStatusListItemId == ModelConstants.AlgoVersionCommitted_StatusId)) && v.Id != version.Id))
    .Select(version => new AlgoVersionCacheItem
        {
            OrderId = version.OrderId,
            OrderTitle = version.Order.Title,
                CurrentVersion = version.Order.CurrentAlgoVersionId,
                CachedVersion = version.Id,
                AvailableVersions = version
                    .Order
                    .AlgoVersions
                    .Where(v => (allowUncommittedVersions || v.Statuses.Any(s => s.AlgoVersionStatusListItemId == ModelConstants.AlgoVersionCommitted_StatusId)) && v.Id != version.Id)
                    .OrderByDescending(v => v.Id) // this line will cause exception
                    .Select(v => v.Id)
        })
    .OrderByDescending(item => item.OrderId)
    .ToArray();

I also have a feeling that this query could be simplified if you go from the other side of relationship (i.e. from Orders) but it may depend on how the someQueryable is created.

like image 104
Pawel Avatar answered Oct 02 '22 14:10

Pawel