Question

I have a linq query involving the following 3 entities:

public class LandPoint
{
    ...
    public OlsonTimeZone TimeZone { get; set; }
}

public class OlsonTimeZone : TimeZone
{
    ...
    public virtual ICollection<WindowsTimeZone> Windows { get; set; }
}

public class WindowsTimeZone : TimeZone
{
    ...
    public virtual ICollection<OlsonTimeZone> Olson { get; set; }
}

So a LandPoint has an OlsonTimeZone which has zero or more WindowsTimeZones.

What I am trying to do is get the WindowsTimeZone name (prefixed by 'Windows:') if the OlsonTimeZone has any WindowsTimeZones or the OlsonTimeZone name (prefixed by 'Olson:') as a fall back along with information about the point itself.

What I have written is:

 return db.LandPoints.Where(x => x.GeoNameID == ID).Take(1).Select(x => new LandPoint
        {
            TimeZone = x.TimeZone
                            .Windows.Select(t => "Windows:" + x.Name)
                            .Union(new[] { "Olson:" + x.TimeZone.Name })
                            .FirstOrDefault()
        }).First();

Which should in theory do what I want. Except that for a given point that I tested it with (which I know has a WindowsTimeZone associated with) it returned the OlsonTimeZone instead of the WindowsTimeZone. If for the same ID i write the following:

return db.LandPoints.Where(x => x.GeoNameID == ID).Take(1).Select(x => new LandPoint
        {
            TimeZone = x.TimeZone
                            .Windows.Select(t => "Windows:" + x.Name)
                            .FirstOrDefault()
        }).First();

I get the WindowsTimeZone.

I am sure I could rewrite it using a CASE statement but I felt this was more elegant. Since the way its behaving is somewhat counter intuitive and understanding why it is doing what it does would help me get a better feeling of how linq queries translate to sql I decided to post a question here.

So why is it doing what it does? Is there some addition to the code above that would make it work (maintaining the UNION statement)?

Thanks in advance John

Was it helpful?

Solution

It is because union doesn't guarantee ordering. You cannot put any special expectations based on order of items without ordering them. But your code should fire NotSupportedException because this is not allowed: db.LandPoints.Select(x => new LandPoint ...

If you have LandPoint entity mapped by entity framework you cannot project to this type in Linq-to-entities.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top