Linq компилира заявки, без да предава контекста

Помислете за тази компилирана linq-to-sql заявка:

private static Func<LINQDBDataContext, string, IQueryable<Pet>> 
    QueryFindByName =
    CompiledQuery.Compile((
    MyLinqDataContext context, string name) =>
    from p in context.Pets where p.Name == name select p);

Но вече имам частна препратка към контекста в класа и искам да мога да маркирам заявката като публична, без да излагам контекста, напр.

private static MyLinqDataContext context = SomeUtilityClass.GetMeMyContext();
//...
public static Func<string, IQueryable<Pet>> QueryFindByName = 
    CompiledQuery.Compile((string name) =>
    from p in this.context.Pets where p.Name == name select p); 
    //doesn't compile as expects TArg0 to be a DataContext.

Има ли някакъв начин да направите това, без да създавате публична обвивка за всяка заявка??


person ctrlalt3nd    schedule 18.02.2009    source източник


Отговори (1)


Вашата препратка към контекста статична ли е, т.е. имате един контекст в целия тип? Това не ми звучи като добра идея. Както и да е, оставяйки това настрана, можете да направите:

// Private version which takes a context...
private static Func<LINQDBDataContext, string, IQueryable<Pet>> 
    QueryFindByNameImpl =
    CompiledQuery.Compile((
    LINQDBDataContext context, string name) =>
    from p in context.Pets where p.Name == name select p);

// Public version which calls the private one, passing in the known context
public static Func<string, IQueryable<Pet>> QueryFindByName = 
    name => QueryFindByNameImpl(contextFromType, name);

РЕДАКТИРАНЕ: Добре, ако не харесвате този подход, можете вместо това да опитате да напишете свои собствени общи обвивки около CompiledQuery.Compile. Например:

public static class LinqHelpers
{
    public static Func<TArg0, TResult> Compile<TContext, TArg0, TResult>
        (this TContext context, 
         Expression<Func<TContext, TArg0, TResult>> query)
        where TContext : DataContext
    {
        Func<TContext, TArg0, TResult> compiled = 
            CompiledQuery.Compile(query);
        return arg => compiled(context, arg);
    }
}

(И така нататък за повече параметри.)

Дори не съм опитвал да го компилирам, но мисля, че ще работи. След това бихте го използвали така:

private static MyLinqDataContext context = SomeUtilityClass.GetMeMyContext();

public static Func<string, IQueryable<Pet>> QueryFindByName = context.Compile
    ((LINQDBDataContext context, string name) =>
      from p in context.Pets where p.Name == name select p);

Все още създава обвивка, разбира се, но поне трябва да го направите само на едно място. Ако възражението ви срещу създаването на обвивки е нещо различно от досадата/бъркотията с кода, моля, дайте повече подробности.

person Jon Skeet    schedule 18.02.2009
comment
Наздраве, но това създава функция за обвивка, която се опитвам да избегна. - person ctrlalt3nd; 18.02.2009
comment
Благодаря. Просто си играя и си помислих, че може да е полезна техника. Но е учудващо трудно за постигане ;) - person ctrlalt3nd; 18.02.2009