IQueryable:在不同的上下文中重用查询

时间:2012-07-03 15:49:10

标签: c# linq entity-framework linq-to-entities

可能是一个愚蠢回答的问题,但是:有没有办法定义一个IQueryable,然后在不同的上下文中重用它?

Somethink喜欢(Pseudocode):

public IQueryable<myItem> MyQuery()
{
   using(MyContext context = new MyContext())
   {
        return (from myItem in context.MyItems
                select ...);
   }
}

这将以下面的“某种”方式使用。

public void MyMethod()
{
    using(MyContext context = new MyContext())
    {
        context.ExecuteQueryUnderContext(MyQuery());
    }

    using(MyContext context2 = new MyContext())
    {
        context2.ExecuteQueryUnderContext(MyQuery());
    }
}

由于

5 个答案:

答案 0 :(得分:2)

你可以使用编译的查询;

public static readonly Func<MyContext, IQueryable<MyItem>> dbGetMyItems =
CompiledQuery.Compile<MyContext, IQueryable<MyItem>>
(context) => from myItem in context.MyItems
                select ...);

然后称之为;

public void MyMethod()
{
    using(MyContext context = new MyContext())
    {
      var query = dbGetMyItems(context);
    }
}

这也为您提供了缓存查询计划的好处,从而提高了性能

答案 1 :(得分:2)

您可以将查询定义为未知现有查询的函数:

// You can add any paramaters you want to this method
// You can also turn this into an extension method
public Func<IQueryable<TItem>, IQueryable<TItem>> MyQuery()
{
   return (IQueryable<TItem> items) => (items.Select...);
}

然后像这样使用它:

using (var context = new MyContext())
{
    return MyQuery(context.Items).ToList();
}

或者像这样:

using (var context = new MyContext())
{
    return MyQuery(context.Items.Where(item.Size > 3)).FirstOrDefault();
}

这样您就可以重复使用甚至链接查询。

或者甚至喜欢这样:

public Item GetItem(Func<IQueryable<TItem>, IQueryable<TItem>> query)
{
    using (var context = new MyContext())
    {
        return query(context.Items).SingleOrDefault();
    }
}

答案 2 :(得分:1)

我会将上下文作为Query方法的参数传递

public IQueryable<myItem> MyQuery(MyContext context)
{

        return (from myItem in context.MyItems
                select ...);
}

public void MyMethod()
{
    using(MyContext context = new MyContext())
    {
      var query = MyQuery(context);
    }
}

答案 3 :(得分:1)

public static class Extension
    {
        public static IQueryable<MyItem> MyQuery(this IQueryable<MyItem> items, int someId)
        {
            return items.Where(x => x.ID == someId);
        }
    }

使用它:

using(MyContext context = new MyContext())
{
       var item = context.MyItems.MyQuery(5);
}

答案 4 :(得分:0)

您可以使用我的助手:

    public static class QueryHelper
{
    static object Get_FieldValue(object obj, string name, bool isBase)
    {
        if (isBase)
        {
            var _internalContext2 = obj.GetType().BaseType.GetField(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField);
            return _internalContext2.GetValue(obj);
        }
        var _internalContext = obj.GetType().GetField(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField);
        return _internalContext.GetValue(obj);
    }

    static FieldInfo Get_Field(object obj, string name, bool isBase)
    {
        if (isBase)
        {
            var _internalContext2 = obj.GetType().BaseType.GetField(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField);
            return _internalContext2;
        }
        var _internalContext = obj.GetType().GetField(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField);
        return _internalContext;
    }

    static object Get_PropertyValue(object obj, string name, bool isBase)
    {
        if (isBase)
        {
            var _internalContext2 = obj.GetType().BaseType.GetProperty(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
            return _internalContext2.GetValue(obj);
        }
        var _internalContext = obj.GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        return _internalContext.GetValue(obj);
    }

    static PropertyInfo Get_Property(object obj, string name, bool isBase)
    {
        if (isBase)
        {
            var _internalContext2 = obj.GetType().BaseType.GetProperty(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
            return _internalContext2;
        }
        var _internalContext = obj.GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        return _internalContext;
    }

    public static void SetInternalContextOfQuery(object old, object newobj)
    {
        var _internalQuery = Get_Field(old, "_internalQuery", false);
        var value = _internalQuery.GetValue(old);
        var _internalContext = Get_Field(value, "_internalContext", false);
        var _newInternalContext = Get_Property(newobj, "InternalContext", false);
        var _internalContextValue = _newInternalContext.GetValue(newobj);

        _internalContext.SetValue(value, _internalContextValue);

        var _ObjectContext = Get_Property(_internalContextValue, "ObjectContext", false);
        var _ObjectContextValue = _ObjectContext.GetValue(_internalContextValue);

        var _objectQuery = Get_Field(value, "_objectQuery", false);
        var _objectQueryValue = _objectQuery.GetValue(value);

        var _providerProperty = Get_Property(_objectQueryValue, "ObjectQueryProvider", false);
        var justV = _providerProperty.GetValue(_objectQueryValue);

        var _provider = Get_Field(_objectQueryValue, "_provider", true);
        var _providerValue = _provider.GetValue(_objectQueryValue);
        var _provider_context = Get_Field(_providerValue, "_context", false);

        var context = Get_Property(_objectQueryValue, "Context", false);

        _provider_context.SetValue(_providerValue, _ObjectContextValue);

        var _query = Get_Property(_objectQueryValue, "QueryState", false);
        var _queryValue = _query.GetValue(_objectQueryValue);
        var _query_context = Get_Field(_queryValue, "_context", true);

        //context.SetValue(_objectQueryValue, _ObjectContextValue);

        _query_context.SetValue(_queryValue, _ObjectContextValue);

        var expersionProperty = Get_Property(value, "Expression", false);
        var expersion = (System.Linq.Expressions.MethodCallExpression)Get_PropertyValue(value, "Expression", false);
        var result = System.Linq.Expressions.Expression.Lambda(expersion).Compile();
        var target = (System.Runtime.CompilerServices.Closure)Get_PropertyValue(result, "Target", false);
        var exProvider = Get_FieldValue(target.Constants[0], "_provider", true);
        var exProviderField = Get_Field(exProvider, "_context", false);

        exProviderField.SetValue(exProvider, _ObjectContextValue);

        var ex_queryProvider = Get_PropertyValue(target.Constants[0], "QueryState", true);
        var ex_queryProviderField = Get_Field(ex_queryProvider, "_context", true);
        //System.Linq.Expressions.Expression.Call()
        ex_queryProviderField.SetValue(ex_queryProvider, _ObjectContextValue);

        var ObjectQuery = Get_PropertyValue(value, "ObjectQuery", false);
        var QueryState = Get_PropertyValue(ObjectQuery, "QueryState", false);
        var _expression = Get_Field(QueryState, "_expression", false);
        var a = expersion.Arguments.ToArray();
        List<System.Linq.Expressions.ConstantExpression> items = new List<System.Linq.Expressions.ConstantExpression>();
        foreach (var item in ((System.Runtime.CompilerServices.Closure)result.Target).Constants)
        {
            items.Add(System.Linq.Expressions.Expression.Constant(item));
        }
        System.Linq.Expressions.MethodCallExpression methodCall =
            System.Linq.Expressions.Expression.Call(expersion.Method, items);

        //var exV=  System.Linq.Expressions.Expression.Lambda(methodCall);
        _expression.SetValue(QueryState, methodCall);
    }
}

用法:

                    IQueryable<DataBase.Models.UserInfo> query = null;
                    using (var context = new HealthFamilyContext(false))
                    {
                        query = from p in context.UserInfoes where p.Id == 1 select p;
                    }

                    using (var context = new HealthFamilyContext(false))
                    {
                        QueryHelper.SetInternalContextOfQuery(query, context);

                        var data = query.ToList();
                    }