views:

297

answers:

4

Hi,

using Linq-to-SQL I'd like to prefetch some data.

1) the common solution is to deal with DataLoadOptions, but in my architecture it won't work because :

  • the options have to be set before the first query
  • I'm using IOC, so I don't directly instanciate the DataContext (I cannot execute code at instanciation)
  • my DataContext is persistent for the duration of a web request

2) I have seen another possibility based on loading the data and its childs in a method, then returning only the data (so the child is already loaded) see an example here

Nonetheless, in my architecture, it cannot not work :

  • My queries are cascaded out of my repository and can be consumed by many services that will add clauses
  • I work with interfaces, the concrete instances of the linq-to-sql objects do not leave the repositories (yes, you can work with interfaces AND add clauses)
  • My repositories are generic

Yes, this architecture is quiet complicated, but it's very cool as I can play with the code like lego ;)

My question is : what are the other possibilities to prefetch a data ?

+1  A: 

I'm not aware of other possibilities, it seems like you've pushed LinqToSql to its limits (I may be wrong, however).

I think your best options at this point are:

  1. Add some "non-generic" methods to your application to handle just the specific scenarios where you want/need eager loading and don't use your "normal", "generic" infrastructure for those methods.
  2. Use an ORM that has more sophisticated support for eager and lazy loading.
Michael Maddox
Thanks for your answers1) I can put some non generic code, but the real problem is that I really want my layers to be separated. My queries are manipulated by the service layer and the database call is triggered by them (transparently), and I don't want to add trick code into them ;)Loose coupling must be paid :p2) You may be right. It's too late for the current project, but for the next one I'll do some testing with other ORM. Any advise ? Ideally something compliant with linq would be great (I really enjoy using it)
Mose
Loose coupling sometimes comes at a cost of increased complexity. It's your choice how you want to make that tradeoff. NHibernate has sophisticated support for eager and lazy loading and also supports Linq, but there may be other ORMs that meet those requirements as well.
Michael Maddox
A: 

I found a solution. My answer is 'Dependency injection'.

It's generally shipped with IOC, and mean you can have your IOC container manage injection of classes at instanciation.

All I need is to inject a CustomDCParameter class when I instanciate a DC. That class will contains the rules, and the constructor will apply all of them.

Mose
A: 

This might be a solution to the DataLoadOptions and seems similar to your posted answer with regard to DI-

This is how i create my DataContext in my DAL:

public class SqlRepositoryRegistry : Registry
{
    public SqlRepositoryRegistry()
    {
        string dbConnStr = String.Empty;
        if (ConfigurationManager.AppSettings["ActiveDbConnectionString"] == null ||
            ConfigurationManager.AppSettings["ActiveDbConnectionString"] == "KsisOnline2_local")
        {
            // must be running tests - so use local
            dbConnStr = DataAccessConstants.CONNSTR_LOCALINTTESTS;

            ForRequestedType<LinqKsisOnline2DataContext>()
                .TheDefault.Is.ConstructedBy(
                    () => new LinqKsisOnline2DataContext(dbConnStr) { Log = new MattyLib.Diagnostics.DebuggerWriter() }
                );
        }
        else
        {
            dbConnStr = ConfigurationManager.ConnectionStrings[ConfigurationManager.AppSettings["ActiveDbConnectionString"].ToString()].ConnectionString;

            ForRequestedType<LinqKsisOnline2DataContext>()
                .TheDefault.Is.ConstructedBy(
                    () => new LinqKsisOnline2DataContext(dbConnStr)
                );
        }

        ForRequestedType<LinqKsisOnline2DataContext>()
            .CacheBy(InstanceScope.Hybrid);
    }
}

..if you're familiar with StructureMap you'll recognise the 'Registry' class design. It's a lot of example, but the point is simple - i can control exactly how i instantiate my dc even when i'm using DI. You can see i want to do things differently when i'm running tests - so i can get verbose logging output from LinqToSql.

cottsak
I actually don't recommend this solution. I prefer the other answer i posted. I added this coz i thought it would be good to know how you can use the `DataLoadOptions` with LinqToSql `DataContext`'s while using DI.
cottsak
+1  A: 

I actually prefer this solution however:

In my app i use perhaps a variation to your potential solution #2. It's somewhat difficult to explain but simply: i chain and defer lazy loading in my model with custom lazy classes so as to abstract away from the LinqToSql-specific Differed Execution that i take advantage of with IQueryable. Benefits:

  • My Domain Model and Service layer upwards does not necessarily have to depend on the LinqToSql provider (i can swap out my DAL with interfaces if i want to)
  • My Service methods can and do return complete object graphs with multiple 'anchor points' for lazy loading using classes that abstract away a particular lazy loading implementation - so i can use LinqToSql-specific Differed Execution or something else (eg. anon delegates. again, refer to this answer)
  • I can maintain IQueryable results throughout my app (even to the UI if i want to) thus allowing infinite LINQ query chaining without having to worry about performance.
cottsak
Thanks, it's a very interesting solution. It's centred on the data object, which I find better. Unfortunately it doesn't answer my current need as my whole architecture is based on lazy loading and the fetched properties are the exception ! I will however try to create a FetchItem<T> and FetchList<T> based on this 'data-object-centric' way of writing, because I really like it. I'm thinking about using attributes to auto-generated the 'CustomDCParameter' class I was talking before. I'll share if I find an acceptable solution (when I have time to work on it). Still listening for good advices
Mose
I think you may be misunderstanding me - when you say 'fetched' do you mean immediate loading from the db? as opposed to lazy/delay loading?
cottsak