Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linq To SQL OrderBy, issue when using enums

I am having some issues with using the OrderBy extension method on a LINQ query when it is operating on an enum type. I have created a regular DataContext using visual studio by simply dragging and dropping everything onto the designer. I have then created seperate entity models, which are simply POCO's, and I have used a repository pattern to fetch the data from my database and map them into my own entity models (or rather, I have a repository pattern, that builds up and IQueryable that'll do all this).

Everything works just fine, except when I try to apply an OrderBy (outside of the repository) on a property that I have mapped from short/smallint to an enum.

Here are the relevant code bits:

public class Campaign
{
    public long Id { get; set; }
    public string Name { get; set; }
    ....
    public CampaignStatus Status { get; set; }
    ...
}
public enum CampaignStatus : short {
    Active,
    Inactive,
    Todo,
    Hidden
}
public class SqlCampaignRepository : ICampaignRepository
{
...
    public IQueryable<Campaign> Campaigns()
    {
        DataContext db = new DataContext();
        return from c in db.Campaigns
                select new Campaign
                   {
                       Id = c.Id,
                       Name = c.Name,
                       ...
                       Status = (CampaignStatus)c.Status,
                       ...
                   };
     }
}

And then elsewhere

SqlCampaignRepository rep = new SqlCampaignRepository();
var query = rep.Campaigns().OrderBy(c => c.Status);

This triggers the following exception: System.ArgumentException was unhandled by user code Message="The argument 'value' was the wrong type. Expected 'IQMedia.Models.CampaignType'. Actual 'System.Int16'." Source="System.Data.Linq" StackTrace: ved System.Data.Linq.SqlClient.SqlOrderExpression.set_Expression(SqlExpression value) ved System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect(SqlSelect select) ved System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node) ved System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitIncludeScope(SqlIncludeScope scope) ...

(sorry about the danish in there, ved = by/at).

I have tried typecasting the Status to short in the orderBy expression, but that doesn't help it, same if i cast it to the actual enum type as well.

Any help fixing this is greatly appreciated!

like image 808
kastermester Avatar asked Dec 18 '08 15:12

kastermester


People also ask

Is LINQ OrderBy stable?

This method performs a stable sort; that is, if the keys of two elements are equal, the order of the elements is preserved.

What is difference between OrderBy and ThenBy in LINQ?

The OrderBy() Method, first sort the elements of the sequence or collection in ascending order after that ThenBy() method is used to again sort the result of OrderBy() method in ascending order.

Can enums hold strings?

No they cannot. They are limited to numeric values of the underlying enum type.

What is OrderBy in LINQ?

LINQ includes following sorting operators. Sorting Operator. Description. OrderBy. Sorts the elements in the collection based on specified fields in ascending or decending order.


2 Answers

Can you specify the type CampaignStatus directly in your DataContext trough the designer? This way the value is automatically mapped to the enum.

like image 83
bruno conde Avatar answered Nov 01 '22 00:11

bruno conde


What is the relationship between the Campaign class and Campaigns? If Campaigns returns the set of Campaign object, note you can't normally select new a mapped entity.

I wonder if it would work any better if you did the OrderBy before the Select?

One final trick might be to create a fake composable [Function], using trivial TSQL. For example, ABS might be enough. i.e. something like (on the context):

    [Function(Name="ABS", IsComposable=true)] 
    public int Abs(int value) 
    { // to prove not used by our C# code... 
        throw new NotImplementedException(); 
    }

Then try:

  .OrderBy(x => ctx.Abs(x.Status))

I haven't tested the above, but can give it a go later... it works for some other similar cases, though.

Worth a shot...

like image 37
Marc Gravell Avatar answered Oct 31 '22 23:10

Marc Gravell