【问题标题】:How to build a dynamic FROM clause for a LINQ query?如何为 LINQ 查询构建动态 FROM 子句?
【发布时间】:2012-12-10 07:54:03
【问题描述】:

我有一个标准的 LINQ 查询:

var list = from x in SomeDataContext.ViewName
           where //Rest of where clause
           select x;

我想知道是否可以构建动态 LINQ 查询,以便我可以在运行时更改 SomeDataContext.ViewName

我有大约 5 个不同的视图,所有视图都有执行 where 子句所需的基本列,但其他每个视图都有一些不同的列名。

那么是否可以构建查询,以便我可以在运行时在需要时使用不同的上下文?

例子:

public void SomeMethod()
{
    var listA = GetList("DataContext.ViewA");
    var listB = GetList("DataContext.ViewB");
    var listC = GetList("DataContext.ViewC");
}

public List<EntityObject> GetList(string dataContextName)
{
    return (from x in /*HERE I WANT TO USE THE dataContextName*/
           where //Rest of where clause
           select x).ToList();
}

【问题讨论】:

    标签: c# .net linq linq-to-entities entity-framework-4.1


    【解决方案1】:

    您可以使用表达式树来构建动态 LINQ 查询。这是一个例子:http://msdn.microsoft.com/en-us/library/bb882637.aspx

    另一种方法是使用动态 LINQ 库: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

    此处说明了这两种方法: http://www.codeproject.com/Articles/231706/Dynamic-query-with-Linq

    此示例中的谓词生成器使用表达式树方法。

    一般来说,动态 LINQ 更容易实现,但表达式树更安全。

    【讨论】:

    • Expression Trees 看起来像是要走的路,但这会带来很多问题,并且当您开始引入连接时会变得非常复杂......
    【解决方案2】:

    只需添加另一层间接:

    public void SomeMethod()
    {
        var listA = GetList("DataContext.ViewA");
        var listB = GetList("DataContext.ViewB");
        var listC = GetList("DataContext.ViewC");
    }
    
    public List<EntityObject> GetList(string dataContextName)
    {
        return (from x in GetSpecificSource(dataContextName)
               where //Rest of where clause
               select x).ToList();
    }
    
    public IEnumerable<MyType> GetSpecificSource(string dataContextName)
    // Or: public IQueryable<MyType> GetSpecificSource(string dataContextName)
    {
        // ToDo: Return the correct source depending on the name. E.g.:
        switch(dataContextName)
        {
            case "DataContext.ViewA":
                return DataContext.ViewA;
            case "DataContext.ViewB":
                return DataContext.ViewB;
            case "DataContext.ViewC":
                return DataContext.ViewC;
        }
    }
    

    关于如何使用反射的更新

    从具有所需名称的字段中检索值:

    var fieldName = "ViewA";
    var fieldFound = type.GetField(fieldName, BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
    
    if(fieldFound != null)
    {
        return fieldFound.GetValue(instance);
    }
    

    从具有所需名称的属性中检索值:

    var propertyName = "ViewA";
    var propertyFound = type.GetProperty(propertyName, BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
    
    if(propertyFound != null)
    {
        return propertyFound.GetValue(instance, null);
    }
    

    从具有所需名称的方法中检索值:

    var methodName = "ViewA";
    var methodFound = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
    
    if(methodFound != null)
       && methodFound.GetParameters().Length == 0)
    {
        return methodFound.Invoke(instance, null);
    }
    

    到目前为止,这些只是一些简单的示例。反思开辟了一个全新的问题和问题包。只需从上面的示例开始,检查它是否满足您的需求。否则,只需返回一个新问题。 ;-)

    【讨论】:

    • 这一切都很好,但我想保持它的通用性。如果我添加 20 个其他视图会怎样。我不想再添加 20 个额外的 case 语句...如果 ViewName 发生更改,那么您硬编码的现有 3 个将无法工作...
    • @Willem:switch case 是最简单的实现。另一种是Dictionary&lt;string, IEnumerable&lt;MyType&gt;&gt;,或者您可以使用反射来查找具有给定上下文名称的字段或属性。在任何情况下,您都必须通过给定的字符串查找对象,在这种情况下,您可以硬编码(通过 switch 或 dict)或使用反射。
    • 好的,反射听起来好一点。我真的不想硬编码任何东西。那么,我将如何使用反射获得正确的“视图”?可以举个例子吗?
    猜你喜欢
    • 2012-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多