0

In controller I have a query and its result will be displayed in the View.

This is how the query result model looks like:

    public class Timesheet
    {
        [Key]
        public virtual int TimesheetId { get; set; }

        [Required]
        public virtual int TimesheetWeek { get; set; }

        [Required]
        public virtual DateTime TimesheetWeekStarts { get; set; }

        [Required]
        public virtual DateTime TimesheetWeekEnds { get; set; }

        [Required]
        public virtual string TimesheetOwner { get; set; }

        [Required]
        public virtual ICollection<TimesheetEntry> TimesheetEntries { get; set; }
    }

And here is the TimesheetEntry model:

public class TimesheetEntry
{
    [Key]
    public virtual int EntryId { get; set; }

    [Required]
    public virtual DateTime EntryDate { get; set; }

    [Required]
    public virtual double TotalHours { get; set; }

    public Timesheet Timesheet { get; set; }

    [Display(Name = "Project number")]
    [ForeignKey("Project")]
    public virtual int ProjectId { get; set; }
    public virtual Project Project { get; set; }
}

The query will always return only one Timesheet class, with multiple TimesheetEntries. Usually I would expect the number of entries to be certain number. Lets say in this case it should be 56. So if the

    TimesheetEntries.Count() != 56

I will add additional entries manually to the query result to ensure that the number of entries is as required. Once done, I will order entries by Date.

    TimesheetEntries.OrderBy(x => x.EntryDate).OrderBy(x => x.Project);

Some Pseudo code to show the process which got me to my problem:

public void PseudoCode()
    {
        const int REQUIRED_NUMBER_OF_ENTRIES = 45;

        //this will return only one instance of model due to .FirstOrDefault()
        var result = this.db.Timesheets.Where(x => x.TimesheetWeekStarts <= DateTime.Now).Select(x => x)
            .Where(x => x.TimesheetOwner == User.Identity.Name)
            .FirstOrDefault();

        if (result != null)
        {
            //if number of entries is not what I expect
            if(result.TimesheetEntries.Count() < REQUIRED_NUMBER_OF_ENTRIES)
            {
                //check how many to add
                int entriesMissing = REQUIRED_NUMBER_OF_ENTRIES - result.TimesheetEntries.Count();

                //add missing entries as empty entries
                for (int i = 0; i < entriesMissing; i++)
                {
                    result.TimesheetEntries.Add(
                        new TimesheetEntry
                        {
                            //to shorten this I am only adding DateTime.Now, normaly different times/dates would be added
                            EntryDate = DateTime.Now,
                            TotalHours = 8
                        });
                }
            }
        }

        result.TimesheetEntries.OrderBy(x => x.EntryDate).OrderBy(x => x.ProjectId);
    }

Here is the result of sorting:

Sorting result

so the the list contains ordered DynamicProxies first and then ordered manually added entries.

But the order should have been:

  1. DynamicProxies.TimesheetEntry
  2. TimesheetEntry
  3. TimesheetEntry
  4. DynamicProxies.TimesheetEntry ... etc

Why is this? Why the order result is ordered this way? Or am I doing this completely wrong ...

tereško
  • 58,060
  • 25
  • 98
  • 150
vidriduch
  • 4,753
  • 8
  • 41
  • 63
  • If I had to guess, I would say you were calling that `OrderBy`, *then* adding the "missing" `TimesheetEntries`. That would just append them to the sorted proxies and look like what you're seeing. You haven't posted much relevant code so it's purely a guess though. There's nothing special about proxies that wouldn't allow them to be sorted like any other object. – Ocelot20 Jul 11 '14 at 11:37
  • thank you, but no. I am adding the entries and them they are sorted... – vidriduch Jul 11 '14 at 12:37
  • Can you post the relevant code? Without it, anyone else attempting to answer this question will only be able to make guesses at the problem. Please take a look at this link, particularly the "How to create a Minimal, Complete, and Verifiable Example" section: http://stackoverflow.com/help/how-to-ask – Ocelot20 Jul 11 '14 at 13:19
  • I have added some extra code as requested. thank you, should have done this on the beginning. – vidriduch Jul 11 '14 at 15:00
  • At least one of the issues is explained [here](http://stackoverflow.com/questions/3760001/linq-orderby-versus-thenby). You should not use multiple `OrderBy`. – rsenna Jul 11 '14 at 15:17

1 Answers1

0

The problem is that OrderBy does not sort the set, it returns a sorted IEnumerable. If you want the collection to reflect the OrderBy operation, you have to assign back to it like so:

result.TimesheetEntries = result.TimesheetEntries
                                .OrderBy(x => x.EntryDate)
                                .ThenBy(x => x.ProjectId)
                                .ToList();

Edit - Also, as pointed out by smartcaveman, if you want to sort by multiple columns you should use ThenBy's for all subsequent ordering after the first OrderBy. If you don't use ThenBy(), each OrderBy() will continue to re-baseline the sort on the current OrderBy field.

Ocelot20
  • 10,510
  • 11
  • 55
  • 96