3

I'm working with EF 4.1 code first with an existing database. I have a class that looks like this:

class myClass
{
    [Key]
    [Column("SomeID", Order=0)]
    public int SomeID { get; set; }

    [Key]
    [Column("Dt", Order=1)]
    public DateTime StartDate { get; set; }

    public String SomeValue { get; set; }
    public int SomeOtherValue { get; set; }
}

I'm trying to get the values (i.e. SomeValue, SomeOtherValue) for the record with the latest StartDate for a specific SomeID. My first attempt at the query was this:

(from x in myContext.myClassDbSet
where x.SomeID == myVariable
orderby x.StartDate descending
select x).FirstOrDefault()

This works fine, but I realized that it's not optimal, so I tried changing it to the following:

(from x in myContext.myClassDbSet
where x.SomeID == myVariable
      && x.StartDate == (from x2 in myContext.myClassDbSet
                         where x2.SomeID == x.SomeID
                         select x2.StartDate).Max()
select x).FirstOrDefault()

The SQL that LINQPad generates for this second query can be faster than the first one with the appropriate index on the table (which I'm willing to create). The problem is that this second query throws a SystemArgumentException with the message:

Object of type 'System.Data.Objects.ObjectQuery'1[myClassDbSet]' cannot be converted to type 'System.Data.Entity.DbSet'1[myClassDbSet]'.

This is thrown in the query declaration, not when trying to execute it.

The weirdest thing is that the same query (literally copy and pasted) in a different class works fine. Anyone know what I'm doing wrong?

vlad
  • 4,748
  • 2
  • 30
  • 36
  • Are you passing the result of the query to a `DbSet` type? – MilkyWayJoe Jun 19 '12 at 20:36
  • (Using SQL Server) I find it odd that LinqPad thinks a join (that is how your second query where statement will be optimized into) will be faster than a straight Index Scan (which both will be using). With an Index on StartDate, the first one should be technically faster (most likely by Ticks and not even close to Microseconds). – Erik Philips Jun 19 '12 at 20:44
  • @MilkyWayJoe I'm just storing the query in a `var`, then trying to use it as an argument to a different function. The exception is thrown in the declaration of the query, not when trying to use the results. Even if I take out the `FirstOrDefault()`, it still throws the same exception. – vlad Jun 19 '12 at 20:47
  • Have you seen [this](http://stackoverflow.com/questions/7208709/entity-framework-4-1-unable-to-cast-from-dbquery-to-objectquery) question? it's similar to yours and there's a lot of other questions referring to the same error message – MilkyWayJoe Jun 19 '12 at 20:51
  • @MilkyWayJoe interesting question, but it doesn't seem to be the same problem and it's not the same error message. – vlad Jun 19 '12 at 20:58
  • @ErikPhilips the index would be on `SomeID`, not on `StartDate`. I'm not 100% sure that it would really be faster, but I want to test it! – vlad Jun 19 '12 at 21:07
  • @vlad Yes, the join would be on `SomeID`. But how does the Aggregate in get the max value? I ran this query, and for some reason the both gave the exact same execution plan (sql server). – Erik Philips Jun 19 '12 at 21:10

1 Answers1

1

You are probably not going to like this answer but I think if you are going to this much trouble to optimise the sql that linq is outputting then it is easier just to write it in sql.

MikeKulls
  • 2,979
  • 2
  • 25
  • 30