.Net EF Core 2.1 Get DbContext from IQueryable argument











up vote
0
down vote

favorite












I have an IQueryable extension method:



public static void SomeExt<T>(this IQueryable<T> query, DbContext context) {...}


and I would like to know if there is some way to get DbContext from query so that DbContext argument could be removed leaving only:



public static void SomeExt<T>(this IQueryable<T> query) {...}


I have tried something like this
Access DataContext behind IQueryable
but its not working, getting zero fields.



Also there is way to get it from DbSet
Can you get the DbContext from a DbSet?
myDbSet.GetService<'ICurrentDbContext>().Context;

but that's not what I need. I want to get it from Query?



This is the query:
var q = context.Items.Where(a => a.StatusId = 1);



q.SomeExt(context);

vs
q.SomeExt();










share|improve this question
























  • This won't work with just any IQueryable implementation so we have to rely on the underlying types. What is the value of query.GetType().FullName for the IQueryable you want to use this on?
    – Daniel Rothig
    Nov 7 at 22:22










  • For FullName of this Query type (<T> is 'Item') I'm getting: "Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[[EFCore.MyExtensions.Tests.Item, EFCore.MyExtensions.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"
    – borisdj
    Nov 7 at 22:30












  • This is a really peculiar thing to want to do, perhaps you could explain why you need this?
    – DavidG
    Nov 7 at 22:33










  • For BatchDelete as Extension on Query.
    – borisdj
    Nov 7 at 22:35

















up vote
0
down vote

favorite












I have an IQueryable extension method:



public static void SomeExt<T>(this IQueryable<T> query, DbContext context) {...}


and I would like to know if there is some way to get DbContext from query so that DbContext argument could be removed leaving only:



public static void SomeExt<T>(this IQueryable<T> query) {...}


I have tried something like this
Access DataContext behind IQueryable
but its not working, getting zero fields.



Also there is way to get it from DbSet
Can you get the DbContext from a DbSet?
myDbSet.GetService<'ICurrentDbContext>().Context;

but that's not what I need. I want to get it from Query?



This is the query:
var q = context.Items.Where(a => a.StatusId = 1);



q.SomeExt(context);

vs
q.SomeExt();










share|improve this question
























  • This won't work with just any IQueryable implementation so we have to rely on the underlying types. What is the value of query.GetType().FullName for the IQueryable you want to use this on?
    – Daniel Rothig
    Nov 7 at 22:22










  • For FullName of this Query type (<T> is 'Item') I'm getting: "Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[[EFCore.MyExtensions.Tests.Item, EFCore.MyExtensions.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"
    – borisdj
    Nov 7 at 22:30












  • This is a really peculiar thing to want to do, perhaps you could explain why you need this?
    – DavidG
    Nov 7 at 22:33










  • For BatchDelete as Extension on Query.
    – borisdj
    Nov 7 at 22:35















up vote
0
down vote

favorite









up vote
0
down vote

favorite











I have an IQueryable extension method:



public static void SomeExt<T>(this IQueryable<T> query, DbContext context) {...}


and I would like to know if there is some way to get DbContext from query so that DbContext argument could be removed leaving only:



public static void SomeExt<T>(this IQueryable<T> query) {...}


I have tried something like this
Access DataContext behind IQueryable
but its not working, getting zero fields.



Also there is way to get it from DbSet
Can you get the DbContext from a DbSet?
myDbSet.GetService<'ICurrentDbContext>().Context;

but that's not what I need. I want to get it from Query?



This is the query:
var q = context.Items.Where(a => a.StatusId = 1);



q.SomeExt(context);

vs
q.SomeExt();










share|improve this question















I have an IQueryable extension method:



public static void SomeExt<T>(this IQueryable<T> query, DbContext context) {...}


and I would like to know if there is some way to get DbContext from query so that DbContext argument could be removed leaving only:



public static void SomeExt<T>(this IQueryable<T> query) {...}


I have tried something like this
Access DataContext behind IQueryable
but its not working, getting zero fields.



Also there is way to get it from DbSet
Can you get the DbContext from a DbSet?
myDbSet.GetService<'ICurrentDbContext>().Context;

but that's not what I need. I want to get it from Query?



This is the query:
var q = context.Items.Where(a => a.StatusId = 1);



q.SomeExt(context);

vs
q.SomeExt();







entity-framework-core asp.net-core-2.0 dbcontext






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 7 at 23:05

























asked Nov 7 at 21:49









borisdj

5911721




5911721












  • This won't work with just any IQueryable implementation so we have to rely on the underlying types. What is the value of query.GetType().FullName for the IQueryable you want to use this on?
    – Daniel Rothig
    Nov 7 at 22:22










  • For FullName of this Query type (<T> is 'Item') I'm getting: "Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[[EFCore.MyExtensions.Tests.Item, EFCore.MyExtensions.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"
    – borisdj
    Nov 7 at 22:30












  • This is a really peculiar thing to want to do, perhaps you could explain why you need this?
    – DavidG
    Nov 7 at 22:33










  • For BatchDelete as Extension on Query.
    – borisdj
    Nov 7 at 22:35




















  • This won't work with just any IQueryable implementation so we have to rely on the underlying types. What is the value of query.GetType().FullName for the IQueryable you want to use this on?
    – Daniel Rothig
    Nov 7 at 22:22










  • For FullName of this Query type (<T> is 'Item') I'm getting: "Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[[EFCore.MyExtensions.Tests.Item, EFCore.MyExtensions.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"
    – borisdj
    Nov 7 at 22:30












  • This is a really peculiar thing to want to do, perhaps you could explain why you need this?
    – DavidG
    Nov 7 at 22:33










  • For BatchDelete as Extension on Query.
    – borisdj
    Nov 7 at 22:35


















This won't work with just any IQueryable implementation so we have to rely on the underlying types. What is the value of query.GetType().FullName for the IQueryable you want to use this on?
– Daniel Rothig
Nov 7 at 22:22




This won't work with just any IQueryable implementation so we have to rely on the underlying types. What is the value of query.GetType().FullName for the IQueryable you want to use this on?
– Daniel Rothig
Nov 7 at 22:22












For FullName of this Query type (<T> is 'Item') I'm getting: "Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[[EFCore.MyExtensions.Tests.Item, EFCore.MyExtensions.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"
– borisdj
Nov 7 at 22:30






For FullName of this Query type (<T> is 'Item') I'm getting: "Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[[EFCore.MyExtensions.Tests.Item, EFCore.MyExtensions.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"
– borisdj
Nov 7 at 22:30














This is a really peculiar thing to want to do, perhaps you could explain why you need this?
– DavidG
Nov 7 at 22:33




This is a really peculiar thing to want to do, perhaps you could explain why you need this?
– DavidG
Nov 7 at 22:33












For BatchDelete as Extension on Query.
– borisdj
Nov 7 at 22:35






For BatchDelete as Extension on Query.
– borisdj
Nov 7 at 22:35














2 Answers
2






active

oldest

votes

















up vote
1
down vote













Sounds like you want to implement ActiveRecord in Entity Framework. Many have tried... Best I can suggest is make your context.Items property something LINQ-like that bootlegs the context, e.g:



public class MyContext : DbContext
{
QueryableWithContext<Item> Items {get => new QueryableWithContext<Item>(ItemsSet, this)}
private DbSet<Item> ItemsSet {get;set;}
}

public class QueryableWithContext<T>
{
public DbContext Context { get; }
private IQueryable<T> inner;

public QueryableWithContext(IQueryable<T> inner, DbContext context)
{
this.inner = inner;
this.Context = context;
}

public QueryableWithContext<T> Where(Func<T,bool> predicate)
{
return new QueryableWithContext<T>(inner.Where(predicate) as IQueryable<T>, Context);
}

// plus lots of other LINQ-like expressions
}


Then your extension method is not on IQueryable<T> but on QueryableWithContext<T>, and can access the Context property.






share|improve this answer





















  • Nice idea, but requires separate QueryableWithContext for each set, so not ideal. I just might stick with sending Context as argument.
    – borisdj
    Nov 8 at 7:18










  • Yep I'd recommend that
    – Daniel Rothig
    Nov 8 at 23:52


















up vote
0
down vote













I have found a way to do this



public static DbContext GetDbContext(IQueryable query)
{
var bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
var queryCompiler = typeof(EntityQueryProvider).GetField("_queryCompiler", bindingFlags).GetValue(query.Provider);
var queryContextFactory = queryCompiler.GetType().GetField("_queryContextFactory", bindingFlags).GetValue(queryCompiler);

var dependencies = typeof(RelationalQueryContextFactory).GetProperty("Dependencies", bindingFlags).GetValue(queryContextFactory);
var queryContextDependencies = typeof(DbContext).Assembly.GetType(typeof(QueryContextDependencies).FullName);
var stateManagerProperty = queryContextDependencies.GetProperty("StateManager", bindingFlags | BindingFlags.Public).GetValue(dependencies);
var stateManager = (IStateManager)stateManagerProperty;
stateManager = stateManager ?? (((LazyRef<IStateManager>)stateManagerProperty)?.Value ?? ((dynamic)stateManagerProperty).Value);

return stateManager.Context;
}





share|improve this answer





















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53198376%2fnet-ef-core-2-1-get-dbcontext-from-iqueryable-argument%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    1
    down vote













    Sounds like you want to implement ActiveRecord in Entity Framework. Many have tried... Best I can suggest is make your context.Items property something LINQ-like that bootlegs the context, e.g:



    public class MyContext : DbContext
    {
    QueryableWithContext<Item> Items {get => new QueryableWithContext<Item>(ItemsSet, this)}
    private DbSet<Item> ItemsSet {get;set;}
    }

    public class QueryableWithContext<T>
    {
    public DbContext Context { get; }
    private IQueryable<T> inner;

    public QueryableWithContext(IQueryable<T> inner, DbContext context)
    {
    this.inner = inner;
    this.Context = context;
    }

    public QueryableWithContext<T> Where(Func<T,bool> predicate)
    {
    return new QueryableWithContext<T>(inner.Where(predicate) as IQueryable<T>, Context);
    }

    // plus lots of other LINQ-like expressions
    }


    Then your extension method is not on IQueryable<T> but on QueryableWithContext<T>, and can access the Context property.






    share|improve this answer





















    • Nice idea, but requires separate QueryableWithContext for each set, so not ideal. I just might stick with sending Context as argument.
      – borisdj
      Nov 8 at 7:18










    • Yep I'd recommend that
      – Daniel Rothig
      Nov 8 at 23:52















    up vote
    1
    down vote













    Sounds like you want to implement ActiveRecord in Entity Framework. Many have tried... Best I can suggest is make your context.Items property something LINQ-like that bootlegs the context, e.g:



    public class MyContext : DbContext
    {
    QueryableWithContext<Item> Items {get => new QueryableWithContext<Item>(ItemsSet, this)}
    private DbSet<Item> ItemsSet {get;set;}
    }

    public class QueryableWithContext<T>
    {
    public DbContext Context { get; }
    private IQueryable<T> inner;

    public QueryableWithContext(IQueryable<T> inner, DbContext context)
    {
    this.inner = inner;
    this.Context = context;
    }

    public QueryableWithContext<T> Where(Func<T,bool> predicate)
    {
    return new QueryableWithContext<T>(inner.Where(predicate) as IQueryable<T>, Context);
    }

    // plus lots of other LINQ-like expressions
    }


    Then your extension method is not on IQueryable<T> but on QueryableWithContext<T>, and can access the Context property.






    share|improve this answer





















    • Nice idea, but requires separate QueryableWithContext for each set, so not ideal. I just might stick with sending Context as argument.
      – borisdj
      Nov 8 at 7:18










    • Yep I'd recommend that
      – Daniel Rothig
      Nov 8 at 23:52













    up vote
    1
    down vote










    up vote
    1
    down vote









    Sounds like you want to implement ActiveRecord in Entity Framework. Many have tried... Best I can suggest is make your context.Items property something LINQ-like that bootlegs the context, e.g:



    public class MyContext : DbContext
    {
    QueryableWithContext<Item> Items {get => new QueryableWithContext<Item>(ItemsSet, this)}
    private DbSet<Item> ItemsSet {get;set;}
    }

    public class QueryableWithContext<T>
    {
    public DbContext Context { get; }
    private IQueryable<T> inner;

    public QueryableWithContext(IQueryable<T> inner, DbContext context)
    {
    this.inner = inner;
    this.Context = context;
    }

    public QueryableWithContext<T> Where(Func<T,bool> predicate)
    {
    return new QueryableWithContext<T>(inner.Where(predicate) as IQueryable<T>, Context);
    }

    // plus lots of other LINQ-like expressions
    }


    Then your extension method is not on IQueryable<T> but on QueryableWithContext<T>, and can access the Context property.






    share|improve this answer












    Sounds like you want to implement ActiveRecord in Entity Framework. Many have tried... Best I can suggest is make your context.Items property something LINQ-like that bootlegs the context, e.g:



    public class MyContext : DbContext
    {
    QueryableWithContext<Item> Items {get => new QueryableWithContext<Item>(ItemsSet, this)}
    private DbSet<Item> ItemsSet {get;set;}
    }

    public class QueryableWithContext<T>
    {
    public DbContext Context { get; }
    private IQueryable<T> inner;

    public QueryableWithContext(IQueryable<T> inner, DbContext context)
    {
    this.inner = inner;
    this.Context = context;
    }

    public QueryableWithContext<T> Where(Func<T,bool> predicate)
    {
    return new QueryableWithContext<T>(inner.Where(predicate) as IQueryable<T>, Context);
    }

    // plus lots of other LINQ-like expressions
    }


    Then your extension method is not on IQueryable<T> but on QueryableWithContext<T>, and can access the Context property.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 7 at 23:45









    Daniel Rothig

    5448




    5448












    • Nice idea, but requires separate QueryableWithContext for each set, so not ideal. I just might stick with sending Context as argument.
      – borisdj
      Nov 8 at 7:18










    • Yep I'd recommend that
      – Daniel Rothig
      Nov 8 at 23:52


















    • Nice idea, but requires separate QueryableWithContext for each set, so not ideal. I just might stick with sending Context as argument.
      – borisdj
      Nov 8 at 7:18










    • Yep I'd recommend that
      – Daniel Rothig
      Nov 8 at 23:52
















    Nice idea, but requires separate QueryableWithContext for each set, so not ideal. I just might stick with sending Context as argument.
    – borisdj
    Nov 8 at 7:18




    Nice idea, but requires separate QueryableWithContext for each set, so not ideal. I just might stick with sending Context as argument.
    – borisdj
    Nov 8 at 7:18












    Yep I'd recommend that
    – Daniel Rothig
    Nov 8 at 23:52




    Yep I'd recommend that
    – Daniel Rothig
    Nov 8 at 23:52












    up vote
    0
    down vote













    I have found a way to do this



    public static DbContext GetDbContext(IQueryable query)
    {
    var bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
    var queryCompiler = typeof(EntityQueryProvider).GetField("_queryCompiler", bindingFlags).GetValue(query.Provider);
    var queryContextFactory = queryCompiler.GetType().GetField("_queryContextFactory", bindingFlags).GetValue(queryCompiler);

    var dependencies = typeof(RelationalQueryContextFactory).GetProperty("Dependencies", bindingFlags).GetValue(queryContextFactory);
    var queryContextDependencies = typeof(DbContext).Assembly.GetType(typeof(QueryContextDependencies).FullName);
    var stateManagerProperty = queryContextDependencies.GetProperty("StateManager", bindingFlags | BindingFlags.Public).GetValue(dependencies);
    var stateManager = (IStateManager)stateManagerProperty;
    stateManager = stateManager ?? (((LazyRef<IStateManager>)stateManagerProperty)?.Value ?? ((dynamic)stateManagerProperty).Value);

    return stateManager.Context;
    }





    share|improve this answer

























      up vote
      0
      down vote













      I have found a way to do this



      public static DbContext GetDbContext(IQueryable query)
      {
      var bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
      var queryCompiler = typeof(EntityQueryProvider).GetField("_queryCompiler", bindingFlags).GetValue(query.Provider);
      var queryContextFactory = queryCompiler.GetType().GetField("_queryContextFactory", bindingFlags).GetValue(queryCompiler);

      var dependencies = typeof(RelationalQueryContextFactory).GetProperty("Dependencies", bindingFlags).GetValue(queryContextFactory);
      var queryContextDependencies = typeof(DbContext).Assembly.GetType(typeof(QueryContextDependencies).FullName);
      var stateManagerProperty = queryContextDependencies.GetProperty("StateManager", bindingFlags | BindingFlags.Public).GetValue(dependencies);
      var stateManager = (IStateManager)stateManagerProperty;
      stateManager = stateManager ?? (((LazyRef<IStateManager>)stateManagerProperty)?.Value ?? ((dynamic)stateManagerProperty).Value);

      return stateManager.Context;
      }





      share|improve this answer























        up vote
        0
        down vote










        up vote
        0
        down vote









        I have found a way to do this



        public static DbContext GetDbContext(IQueryable query)
        {
        var bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
        var queryCompiler = typeof(EntityQueryProvider).GetField("_queryCompiler", bindingFlags).GetValue(query.Provider);
        var queryContextFactory = queryCompiler.GetType().GetField("_queryContextFactory", bindingFlags).GetValue(queryCompiler);

        var dependencies = typeof(RelationalQueryContextFactory).GetProperty("Dependencies", bindingFlags).GetValue(queryContextFactory);
        var queryContextDependencies = typeof(DbContext).Assembly.GetType(typeof(QueryContextDependencies).FullName);
        var stateManagerProperty = queryContextDependencies.GetProperty("StateManager", bindingFlags | BindingFlags.Public).GetValue(dependencies);
        var stateManager = (IStateManager)stateManagerProperty;
        stateManager = stateManager ?? (((LazyRef<IStateManager>)stateManagerProperty)?.Value ?? ((dynamic)stateManagerProperty).Value);

        return stateManager.Context;
        }





        share|improve this answer












        I have found a way to do this



        public static DbContext GetDbContext(IQueryable query)
        {
        var bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
        var queryCompiler = typeof(EntityQueryProvider).GetField("_queryCompiler", bindingFlags).GetValue(query.Provider);
        var queryContextFactory = queryCompiler.GetType().GetField("_queryContextFactory", bindingFlags).GetValue(queryCompiler);

        var dependencies = typeof(RelationalQueryContextFactory).GetProperty("Dependencies", bindingFlags).GetValue(queryContextFactory);
        var queryContextDependencies = typeof(DbContext).Assembly.GetType(typeof(QueryContextDependencies).FullName);
        var stateManagerProperty = queryContextDependencies.GetProperty("StateManager", bindingFlags | BindingFlags.Public).GetValue(dependencies);
        var stateManager = (IStateManager)stateManagerProperty;
        stateManager = stateManager ?? (((LazyRef<IStateManager>)stateManagerProperty)?.Value ?? ((dynamic)stateManagerProperty).Value);

        return stateManager.Context;
        }






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 16 at 15:13









        borisdj

        5911721




        5911721






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53198376%2fnet-ef-core-2-1-get-dbcontext-from-iqueryable-argument%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            這個網誌中的熱門文章

            Academy of Television Arts & Sciences

            L'Équipe

            1995 France bombings