subsonic / SubSonic-3.0-Templates

T4 Template Project for the peeps
http://subsonic.github.io/
105 stars 46 forks source link

Major unintentional performance hit from Find .ToList? #46

Closed sprawl-zz closed 14 years ago

sprawl-zz commented 14 years ago

Ok I'm not sure if this would just be a problem with the T4 Templates or just me being dumb but I was under the impression that using .Find(i=>bool) wouldn't kill my chain of IQueryable operators.

I did performance profiling and everything only to find out that the answer to my abysmal performance was right there in the ActiveRecord.cs generated for my SQLite database:

public static IList Find(Expression<Func<tblSystemsValue, bool>> expression)...

The forced cast to IList was causing severe problems when I tried executing queries like the following:

 var myVal = tblSystemsValue.Find(o => o.tblSystems_ID == 1 && o.ColumnNum == 2)
                   .OrderByDescending(i => i.ID)
                      .FirstOrDefault();

Once I noticed that ActiveRecord.cs was returning IList it made perfect sense why 96% of my application execution time was being spent in IEnumerable.ToList<> and the ctor for my ActiveRecord classes like tblSystemsValue.

I don't really understand why Find isn't returning IQueryable since Repo.Find DOES actually return IQueryable and seems to compile without any issues if I update the ActiveRecord.cs or templates myself.

Is this a concession to some limitation I'm unaware of or just an oversight in the templates?

My application is 100x faster now that I discovered the problem and changed my usage but I'm afraid that a lot of developers would have significant dificulty catching this problem and I didn't see anything in the documentation indicating that I should always prefer tblSomething.All().Where(i=>i.WantThis).OtherLinqStuff() instead of simply tblSomething.Find(i=>i.WantThis).OtherLinqStuff()

Thank You--Love the project and don't want to see people abandon adoption due to 'performance' issues like this!

robconery commented 14 years ago

The thing you want to use for a single is Single, if you want IQueryable back use All(). Find is a subset list.

adam7 commented 14 years ago

Closing as Rob's explained what's going on