Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何根据分层对象列表动态构建和存储复杂的linq查询?_C#_Linq_Linq To Objects_Dynamic Linq - Fatal编程技术网

C# 如何根据分层对象列表动态构建和存储复杂的linq查询?

C# 如何根据分层对象列表动态构建和存储复杂的linq查询?,c#,linq,linq-to-objects,dynamic-linq,C#,Linq,Linq To Objects,Dynamic Linq,我有一个层次结构中的对象列表。我想根据客户公司设置并存储在数据库中的“条件”,针对该对象列表构建复杂的LINQ查询。因此,我需要在运行时构建这些查询,但因为每当客户机的用户更新或刷新其数据时,它们都会重复运行,所以我希望将LINQ查询存储在对象中,而不是每次都重新构建它们 我已经看了ScottGu关于的博客。 本文还介绍了如何使用。 这两种方法似乎都不能提供适当的解决方案,但我可能没有充分理解它们。当我考虑其他选项时,恐怕我在尝试使用LINQ。 我的对象层次结构: WorkOrder[]

我有一个层次结构中的对象列表。我想根据客户公司设置并存储在数据库中的“条件”,针对该对象列表构建复杂的LINQ查询。因此,我需要在运行时构建这些查询,但因为每当客户机的用户更新或刷新其数据时,它们都会重复运行,所以我希望将LINQ查询存储在对象中,而不是每次都重新构建它们

我已经看了ScottGu关于的博客。
本文还介绍了如何使用。
这两种方法似乎都不能提供适当的解决方案,但我可能没有充分理解它们。当我考虑其他选项时,恐怕我在尝试使用LINQ。 我的对象层次结构:

WorkOrder[]
    Field[]
    Task[]
        Field[]
下面是一个我想存储和执行的LINQ查询示例。我可以根据定义条件的数据库记录合理地构建此格式

var query =
from wo in WorkOrders
from woF in wo.Fields
from task in wo.Tasks
from taskF in task.Fields
from taskF2 in task.Fields
where woF.Name == "System Status"
    && woF.Value.Contains("SETC")
    && taskF.Name == "Material"
    && taskF.Value == "Y"
    && taskF2.Name == "Planner"
    && taskF2.Value == "GR5259"
select new
{
    wo_id = wo.ID,
    task_id = task.ID
};
一些考虑

  • 根据用户定义条件的复杂性,我可能需要也可能不需要从不同的对象列表中提取:“from”是动态的
  • 请注意,在本例中,我从task.fields[]中提取了两次,因此我给它加了两次别名
  • 示例LINQ结构允许我使用复杂的AND、or、括号等,但我认为这些对于动态链接或表达式树是不实用的
在我的代码中,我设想:

//1) Retrieve business rules from DB. I can do this.

//2) Iterate through the business rules to build the linq queries.
foreach (BusinessRule br in BusinessRules) {
    //Grab the criteria for the rule from the DB. 

    //Create a linq to object query based on the criteria just built.
    //Add this query to a list for later use.
}

...Elsewhere in application.

//Iterate through and execute the linq queries in order to apply business rules to data cached in the application.
foreach (LinqQuery q in LinqQueries) {
    //Execute the query

    //Apply business rule to the results.
}

非常感谢您的想法、努力和想法。

从技术上讲,您只需使用LINQ即可实现所需的功能,但这是一个很好的实用程序类:

public enum AndOr
{
    And,
    Or
}

public enum QueryableObjects
{
    WorkOrderField,
    TaskField
}

public class ClientCondition
{
    public AndOr AndOr;
    public QueryableObjects QueryableObject;
    public string PropertyName;
    public string PropertyValue;
}

public void PredicateBuilderExample()
{
    var conditions = new List<ClientCondition> {
    {
        new ClientCondition { AndOr = LINQ.AndOr.And,
            QueryableObject = QueryableObjects.WorkOrderField,
            PropertyName = "System Status",
            PropertyValue = "SETC"
        }
    },
    {
        new ClientCondition{AndOr = AndOr.And,
            QueryableObject = QueryableObjects.TaskField,
            PropertyName = "Material",
            PropertyValue = "Y"
        }
    },
    {
        new ClientCondition{AndOr = AndOr.Or,
            QueryableObject = QueryableObjects.TaskField,
            PropertyName = "Planner",
            PropertyValue = "GR5259"
        }
    }
    };

    //Obviously this WorkOrder object is empty so it will always return empty lists when queried.
    //Populate this yourself.
    var WorkOrders = new List<WorkOrder>();

    var wofPredicateBuilder = PredicateBuilder.True<WorkOrderField>();
    var tfPredicateBuilder = PredicateBuilder.True<TaskField>();

    foreach (var condition in conditions)
    {
        if (condition.AndOr == AndOr.And)
        {
            if (condition.QueryableObject == QueryableObjects.WorkOrderField)
            {
                wofPredicateBuilder = wofPredicateBuilder.And(
                    wof => wof.Name == condition.PropertyName &&
                        wof.Value.Contains(condition.PropertyValue));
            }
        }
        if (condition.AndOr == AndOr.Or)
        {
            if (condition.QueryableObject == QueryableObjects.TaskField)
            {
                tfPredicateBuilder = tfPredicateBuilder.Or(
                    tf => tf.Name = condition.PropertyName &&
                        tf.Value.Contains(condition.PropertyValue));
            }
        }
        //And so on for each condition type.
    }

    var query = from wo in WorkOrders
                from woF in wo.Fields.AsQueryable().Where(wofPredicateBuilder)
                from task in wo.Tasks
                from taskF in task.Fields.AsQueryable().Where(tfPredicateBuilder)
                select new
                {
                    wo_id = wo.ID,
                    task_id = task.ID
                };
}
公共枚举和或
{
以及,
或
}
公共枚举QueryableObjects
{
劳德菲尔德,
TaskField
}
公共类ClientCondition
{
公共和或和或;
公共查询对象查询对象;
公共字符串PropertyName;
公共字符串PropertyValue;
}
公共void谓词BuilderExample()
{
var条件=新列表{
{
新客户端条件{和或=LINQ.And或.And,
QueryableObject=QueryableObjects.WorkOrderField,
PropertyName=“系统状态”,
PropertyValue=“SETC”
}
},
{
新客户条件{和或=和或。和,
QueryableObject=QueryableObjects.TaskField,
PropertyName=“材料”,
PropertyValue=“Y”
}
},
{
新客户端条件{和或=和或。或,
QueryableObject=QueryableObjects.TaskField,
PropertyName=“规划器”,
PropertyValue=“GR5259”
}
}
};
//显然,这个WorkOrder对象是空的,所以在查询时它总是返回空列表。
//自己填充这个。
var WorkOrders=新列表();
var wofPredicateBuilder=predictebuilder.True();
var tfPredicateBuilder=PredicateBuilder.True();
foreach(条件中的var条件)
{
如果(条件和或==和或和)
{
if(condition.QueryableObject==QueryableObjects.WorkOrderField)
{
wofPredicateBuilder=wofPredicateBuilder。和(
wof=>wof.Name==condition.PropertyName&&
包含(condition.PropertyValue));
}
}
如果(条件与或==与或或)
{
if(condition.QueryableObject==QueryableObjects.TaskField)
{
tfPredicateBuilder=tfPredicateBuilder。或(
tf=>tf.Name=condition.PropertyName&&
包含(condition.PropertyValue));
}
}
//对于每种条件类型,依此类推。
}
var查询=来自工单中的工单
来自wo.Fields.AsQueryable()中的woF,其中(wofPredicateBuilder)
来自工单中的任务。任务
来自task.Fields.AsQueryable()中的taskF,其中(TFPredicteBuilder)
选择新的
{
wo_id=wo.id,
task\u id=task.id
};
}
请注意,我使用枚举来限制客户端可能发送给您的条件。要拥有一个真正的动态可查询引擎,您需要使用反射来确保收到的对象名称有效。这似乎是一个相当大的范围,在这一点上,我建议研究一种不同的方法,例如


还要注意,And和Ors的顺序非常重要。从本质上讲,您允许您的客户针对您的数据构建SQL查询,而这通常以眼泪告终。您的工作是将它们限制为它们应该查询的适当条件集。

根据与Guillaume的讨论,我建议在使用高级动态查询生成时,只注意结果查询的类型。如果您正在更改通过
选择
聚合
或其他方法返回的内容的形状,您希望您的内部类型会相应更改。如果您只是在筛选,您可以继续添加任意数量的附加案例,除非您需要或需要其他行为,那么PredicateBuilder之类的东西会有所帮助。如果您想通过
Join
Zip
。。。然后,您可以进行筛选,添加到返回的行中,还可以更改数据的形状


我过去做过很多这方面的工作,最成功的是专注于特定的帮助器方法,这些方法允许我需要的常见情况,然后依靠linq表达式树和模式(例如访问者模式)来允许在运行时生成自定义表达式。

什么是“将它们存储在对象中”?储存什么?查询的结果是什么?使用缓存。表情?你会储存什么?这是一个表达。您是想说您想要动态组合查询吗?谢谢您的提问。理想情况下,当应用程序开始时,我可以动态地构建LI