如何为IEnumerable.Any编写Linq.Expression

时间:2015-05-29 06:07:34

标签: c# linq linq-expressions

我在我的代码中编写查询apply plugin: 'com.android.application' android { compileSdkVersion 22 buildToolsVersion "22.0.1" ... 。我对表达式不是很熟悉,我想写一个表达式来检查Linq to Sql中是否有任何项满足条件

IEnumerable

我有如下的查询类:

public class TestClass1
{
    // can be any number of properties, with diff names and types
    public string TestProperty1 { get; set; }
    public string TestProperty2 { get; set; }
    public List<TestClass1ExtraFieldValue> TestClass1ExtraFieldValueList { get; set; }
}

public class TestClass1ExtraFieldValue
{
    public TestClass1ExtraField TestClass1ExtraField { get; set; }

    // property names below are same in all classes which name ends with ExtraFieldValue
    public int IntValue { get; set; }
    public bool BoolValue { get; set; }
    public DateTime DateTimeValue { get; set; }
    public string StringValue { get; set; }
}

public class TestClass1ExtraField
{
    // property names are same in all classes which name ends with ExtraField
    public string Property1 { get; set; }
    public string Property2 { get; set; }
}

public class TestClass2
{
    // can be any number of properties, with diff names and types
    public string TestProperty1 { get; set; }
    public string TestProperty2 { get; set; }
    public List<TestClass2ExtraFieldValue> TestClass2ExtraFieldValueList { get; set; }
}

public class TestClass2ExtraFieldValue
{
    public TestClass2ExtraField TestClass2ExtraField { get; set; }

    // property names below are same in all classes which name ends with ExtraFieldValue
    public int IntValue { get; set; }
    public bool BoolValue { get; set; }
    public DateTime DateTimeValue { get; set; }
    public string StringValue { get; set; }
}

public class TestClass2ExtraField
{
    // property names are same in all classes  which name ends with ExtraField
    public string Property1 { get; set; }
    public string Property2 { get; set; }
}

public class TestClass3
{
    // can be any number of properties, with diff names and types
    public string TestProperty1 { get; set; }
    public string TestProperty2 { get; set; }
    public List<TestClass3ExtraFieldValue> TestClass3ExtraFieldValueList { get; set; }
}

public class TestClass3ExtraFieldValue
{
    public TestClass3ExtraField TestClass3ExtraField { get; set; }

    // property names below are same in all classes which name ends with ExtraFieldValue
    public int IntValue { get; set; }
    public bool BoolValue { get; set; }
    public DateTime DateTimeValue { get; set; }
    public string StringValue { get; set; }
}

public class TestClass3ExtraField
{
    // property names are same in all classes which name ends with ExtraField
    public string Property1 { get; set; }
    public string Property2 { get; set; }
}

// NOT a DB class
public class ExtraFieldClass
{
    public string Property1 { get; set; }
    public string Property2 { get; set; }
    public int IntValue { get; set; }
    public bool BoolValue { get; set; }
    public DateTime DateTimeValue { get; set; }
    public string StringValue { get; set; }
}

现在,如果您看到我的查询类,每个都有自己的条件检查,对于额外的字段,逻辑是相同的,只有名称更改。我有20个类似于此类。而且我不希望每个地方都有相同的重复代码。我搜索并发现我们可以使用public class TestClass1Query { public string TestValue1; public string TestValue2; List<ExtraFieldClass> ExtraFieldsList { get; set; } public IQueryable GetQuery() { var query = GetTestClass1Values().Where(c=> c.TestProperty1==TestValue1 && c.TestProperty2 == TestValue2); // some condition checks foreach (var extraField in ExtraFieldsList) { switch (extraField.Type) { case FieldType.Boolean: { var boolValue = Convert.ToBoolean(extraField.Fieldvalue); query = query.Where(c => c.TestClass1ExtraFieldValueList.Any(t => t.TestClass1ExtraField.Property1 == extraField.Property1 && t.TestClass1ExtraField.Property2 == extraField.Property2 && t.BoolValue == boolValue)); break; } case FieldType.DateTime: { var dateTimeValue = Convert.ToDateTime(extraField.Fieldvalue); query = query.Where(c => c.TestClass1ExtraFieldValueList.Any(t => t.TestClass1ExtraField.Property1 == extraField.Property1 && t.TestClass1ExtraField.Property2 == extraField.Property2 && t.DateTimeValue == dateTimeValue)); break; } case FieldType.Text: { var stringValue = Convert.ToString(extraField.Fieldvalue); query = query.Where(c => c.TestClass1ExtraFieldValueList.Any(t => t.TestClass1ExtraField.Property1 == extraField.Property1 && t.TestClass1ExtraField.Property2 == extraField.Property2 && t.StringValue == stringValue)); break; } case FieldType.Integer: { var integerValue = Convert.ToInt32(extraField.Fieldvalue); query = query.Where(c => c.TestClass1ExtraFieldValueList.Any(t => t.TestClass1ExtraField.Property1 == extraField.Property1 && t.TestClass1ExtraField.Property2 == extraField.Property2 && t.IntValue == integerValue)); break; } } } return query; } private IQueryable<TestClass1> GetTestClass1Values() { return null; } } public class TestClass2Query { public string TestValue1; public string TestValue2; List<ExtraFieldClass> ExtraFieldsList { get; set; } public IQueryable GetQuery() { var query = GetTestClass2Values().Where(c => c.TestProperty1 == TestValue1 && c.TestProperty2 == TestValue2); // some condition checks foreach (var extraField in ExtraFieldsList) { switch (extraField.Type) { case FieldType.Boolean: { var boolValue = Convert.ToBoolean(extraField.Fieldvalue); query = query.Where(c => c.TestClass2ExtraFieldValueList.Any(t => t.TestClass2ExtraField.Property1 == extraField.Property1 && t.TestClass2ExtraField.Property2 == extraField.Property2 && t.BoolValue == boolValue)); break; } case FieldType.DateTime: { var dateTimeValue = Convert.ToDateTime(extraField.Fieldvalue); query = query.Where(c => c.TestClass2ExtraFieldValueList.Any(t => t.TestClass2ExtraField.Property1 == extraField.Property1 && t.TestClass2ExtraField.Property2 == extraField.Property2 && t.DateTimeValue == dateTimeValue)); break; } case FieldType.Text: { var stringValue = Convert.ToString(extraField.Fieldvalue); query = query.Where(c => c.TestClass2ExtraFieldValueList.Any(t => t.TestClass2ExtraField.Property1 == extraField.Property1 && t.TestClass2ExtraField.Property2 == extraField.Property2 && t.StringValue == stringValue)); break; } case FieldType.Integer: { var integerValue = Convert.ToInt32(extraField.Fieldvalue); query = query.Where(c => c.TestClass2ExtraFieldValueList.Any(t => t.TestClass2ExtraField.Property1 == extraField.Property1 && t.TestClass2ExtraField.Property2 == extraField.Property2 && t.IntValue == integerValue)); break; } } } return query; } private IQueryable<TestClass2> GetTestClass2Values() { return null; } } public class TestClass3Query { public string TestValue1; public string TestValue2; List<ExtraFieldClass> ExtraFieldsList { get; set; } public IQueryable GetQuery() { var query = GetTestClass3Values().Where(c => c.TestProperty1 == TestValue1 && c.TestProperty2 == TestValue2); // some condition checks foreach (var extraField in ExtraFieldsList) { switch (extraField.Type) { case FieldType.Boolean: { var boolValue = Convert.ToBoolean(extraField.Fieldvalue); query = query.Where(c => c.TestClass3ExtraFieldValueList.Any(t => t.TestClass3ExtraField.Property1 == extraField.Property1 && t.TestClass3ExtraField.Property2 == extraField.Property2 && t.BoolValue == boolValue)); break; } case FieldType.DateTime: { var dateTimeValue = Convert.ToDateTime(extraField.Fieldvalue); query = query.Where(c => c.TestClass3ExtraFieldValueList.Any(t => t.TestClass3ExtraField.Property1 == extraField.Property1 && t.TestClass3ExtraField.Property2 == extraField.Property2 && t.DateTimeValue == dateTimeValue)); break; } case FieldType.Text: { var stringValue = Convert.ToString(extraField.Fieldvalue); query = query.Where(c => c.TestClass3ExtraFieldValueList.Any(t => t.TestClass3ExtraField.Property1 == extraField.Property1 && t.TestClass3ExtraField.Property2 == extraField.Property2 && t.StringValue == stringValue)); break; } case FieldType.Integer: { var integerValue = Convert.ToInt32(extraField.Fieldvalue); query = query.Where(c => c.TestClass3ExtraFieldValueList.Any(t => t.TestClass3ExtraField.Property1 == extraField.Property1 && t.TestClass3ExtraField.Property2 == extraField.Property2 && t.IntValue == integerValue)); break; } } } return query; } private IQueryable<TestClass3> GetTestClass3Values() { return null; } } 来获得通用代码。

我对编写表达方式没有任何了解,有任何建议或方法可以达到这个目的吗?

1 个答案:

答案 0 :(得分:0)

你写的Linq实际上是转换成了SQL命令。在您的情况下,您创建了相当复杂的Match函数,该函数太复杂,无法自动转换为SQL。

要解决这个问题,您必须从switch方法中提取Match语句并在线创建查询:

var input = new Parameter();
// ...init input
query = query.Where(a => a.Property1 == "sometext");

switch(input.Type)
{
    Case bool:
        var boolValue = Convert.ToBoolean(input.ObjectValue);
        query = query.Where(a => a.Collection.Any(b => b.TestValue.C1 == input.Parameter1 && b.TestValue.C2 == input.Parameter && b.BoolValue == boolValue);
        break;
    Case dateTime :
        // convert to datetime and check
        var dateTimeValue = Convert.ToDateTime(input.ObjectValue);
        query = query.Where(a=> a.Collection.Any(b => b.TestValue.C1 == input.Parameter1 && b.TestValue.C2 == input.Parameter && b.DateTimeValue == dateTimeValue );
        break;
    Case int:
        // convert to int and check
        // ...
        break;
}

不是最好看的代码,但应该有效。

修改

你可以通过将丑陋的部分移动到可以重复使用的单独函数来改进它:

public IQueryable<ITest2> ApplyFilterOnQuery(IQueryable<ITest2> query, Parameter input)
{
    switch(input.Type)
    {
        Case bool:
            var boolValue = Convert.ToBoolean(input.ObjectValue);
            query = query.Where(a => a.Collection.Any(b => b.TestValue.C1 == input.Parameter1 && b.TestValue.C2 == input.Parameter && b.BoolValue == boolValue);
            break;
        Case dateTime :
            // convert to datetime and check
            var dateTimeValue = Convert.ToDateTime(input.ObjectValue);
            query = query.Where(a => a.Collection.Any(b => b.TestValue.C1 == input.Parameter1 && b.TestValue.C2 == input.Parameter && b.DateTimeValue == dateTimeValue );
            break;
        Case int:
            // convert to int and check
            // ...
            break;
    }
    return query;
}

然后你会像这样使用它:

var input = new Parameter();
// ...init input
query = query.Where(a => a.Property1 == "sometext");
query = ApplyFilterOnQuery(query, input);