I have a news table and I would like to implement custom ordering. I have done this before via a positional mapping table which has newsIds and a position.
I then LEFT OUTER JOIN the position table ON news.newsId = position.itemId with a select case statement
CASE WHEN [position] IS NULL THEN 9999 ELSE [position] END
and order by position asc, articleDate desc.
Now I am trying to do the same with Linq to Entities. I have set up my tables with a PK, FK relationship so that my News object has an Entity Collection of positions.
Now comes the bit I can’t work out. How to implement the LEFT OUTER JOIN.
I have so far:
var query = SelectMany (n => n.Positions, (n, s) => new { n, s })
.OrderBy(x => x.s.position)
.ThenByDescending(x => x.n.articleDate)
.Select(x => x.n);
This kinda works. However this uses a INNER JOIN so not what I am after.
I had another idea:
ret = ret.OrderBy(n => n.Positions.Select(s => s.position));
However I get the error DbSortClause expressions must have a type that is order comparable.
I also tried
ret = ret.GroupJoin(tse.Positions, n => n.id, s => s.itemId, (n, s) => new { n, s })
.OrderBy(x => x.s.Select(z => z.position))
.ThenByDescending(x => x.n.articleDate)
.Select(x => x.n);
but I get the same error!
If anyone can help me out, it would be much appreciated!
UPDATE:
So after some playing about I have managed to get it working.
ret = ret.GroupJoin(entity.Positions, n => n.id, s => s.itemId, (n, s) => new { n, s })
.SelectMany(x => x.n.Positions.DefaultIfEmpty(), (n, s) => new { n, s })
.OrderBy(x => x.s.position)
.ThenByDescending(x => x.n.n.articleDate)
.Select(x => x.n.n);
However, this is still not completely right. I have no way of using only a specific positionid or articleType.
If I have news id 1 and a review id but defined in the positions table, currently (I think) the linq query would select both?
If I try and use a where clause, it’s basically the same as inner joining. What I need is to try and use a case in the select like I would do in straight SQL:
CASE WHEN [position] IS NULL OR shuffleId != 1 THEN 9999 ELSE [position] END
I may have to completely rethink how do this. Don’t suppose anyone has any suggestions of alternative methods?
How about:
Ps. the above assumes there is only 1 position entry for each news … just seems weird if that were not the case.
Solution posted by OP in the comment below: