C# 在任何LINQ to SQL表达式中对特定属性重用函数

C# 在任何LINQ to SQL表达式中对特定属性重用函数,c#,linq-to-sql,ef-core-2.0,C#,Linq To Sql,Ef Core 2.0,我有以下代码: var dbContacts = dbContacts.Where(k => k.Name != null && k.Name.ToLower().IndexOf(model.name.ToLower()) > -1); 这太长了,我试图实现以下目标,而不必在多个属性上重复该函数: var dbContacts = dbContacts.Where(k => contains(k.Name,model.name)); // or var d

我有以下代码:

var dbContacts = dbContacts.Where(k => k.Name != null && k.Name.ToLower().IndexOf(model.name.ToLower()) > -1);
这太长了,我试图实现以下目标,而不必在多个属性上重复该函数:

var dbContacts = dbContacts.Where(k => contains(k.Name,model.name));

// or

var dbContacts = dbContacts.Where(k => k.Name.ContainsIgnoreCase(model.name));
我签出了,所有答案都使用
表达式
,其中它重用整个表达式,而不是特定属性上该表达式中的特定函数

然而,到目前为止我所做的尝试(无法翻译得到LINQ表达式):

//定义委托函数
Func contains=(字符串str,字符串值)=>
{
return str!=null&&str.ToLower().IndexOf(value.ToLower())>-1;
};
//使用扩展名
公共静态bool containsSignoreCase(此字符串str,字符串值)
{
返回str.IndexOf(value,StringComparison.OrdinalIgnoreCase)>-1;
}
我希望在任何LINQ to SQL表达式中的特定属性上重用该函数


有什么想法吗?

据我所知,您正在尝试创建一个委托函数,用作Linq查询中的过滤器。因此,最后您需要使用您创建的委托
Func
,如下所示:

var dbContacts = dbContacts.Where(k => contains(k.Name,model.name));
Func<EntityModelClass, bool> contains = (EntityModelClass entity) =>
{
    return entity.Name != null && entity.Name.ToLower().IndexOf(entity.Model.ToLower()) > -1;
};
var contacts = dbContacts.WhereContains("Name", model.name);
这不起作用,因为
Where
接受
Func
,所以需要执行以下操作:

var dbContacts = dbContacts.Where(k => contains(k.Name,model.name));
Func<EntityModelClass, bool> contains = (EntityModelClass entity) =>
{
    return entity.Name != null && entity.Name.ToLower().IndexOf(entity.Model.ToLower()) > -1;
};
var contacts = dbContacts.WhereContains("Name", model.name);
但是,如果您这样做,您的功能可能会更好:

var dbContacts = dbContacts.Where(contains);
!string.IsNullOrEmpty(k.Name) && k.Name.IndexOf(model.name, StringComparison.InvariantCultureIgnoreCase) > -1
更新:

从我在您的评论中了解到的情况来看,您可能正在寻找一种反射解决方案,您只需传递属性名称和模型

以下是一个例子:

public static class LinqExtension
{
    public static IEnumerable<T> WhereContains<T>(this IEnumerable<T> source, string propertyName, string model)
    {
        if(string.IsNullOrEmpty(propertyName)) { throw new ArgumentNullException(nameof(propertyName)); }

        if (string.IsNullOrEmpty(model)) { throw new ArgumentNullException(nameof(model)); }

        foreach (var item in source)
        {
            var property = item.GetType().GetProperty(propertyName);

            if (property == null)
            {
                throw new ArgumentNullException(nameof(property));
            }

            var value = property.GetValue(item, null)?.ToString();

            if (!string.IsNullOrEmpty(value) || value.IndexOf(model, StringComparison.InvariantCultureIgnoreCase) > -1)
            {
                yield return item;
            }
        }
    }
}

我希望这就是你要找的

据我所知,您正在尝试创建一个委托函数,用作Linq查询中的过滤器。因此,最后您需要使用您创建的委托
Func
,如下所示:

var dbContacts = dbContacts.Where(k => contains(k.Name,model.name));
Func<EntityModelClass, bool> contains = (EntityModelClass entity) =>
{
    return entity.Name != null && entity.Name.ToLower().IndexOf(entity.Model.ToLower()) > -1;
};
var contacts = dbContacts.WhereContains("Name", model.name);
这不起作用,因为
Where
接受
Func
,所以需要执行以下操作:

var dbContacts = dbContacts.Where(k => contains(k.Name,model.name));
Func<EntityModelClass, bool> contains = (EntityModelClass entity) =>
{
    return entity.Name != null && entity.Name.ToLower().IndexOf(entity.Model.ToLower()) > -1;
};
var contacts = dbContacts.WhereContains("Name", model.name);
但是,如果您这样做,您的功能可能会更好:

var dbContacts = dbContacts.Where(contains);
!string.IsNullOrEmpty(k.Name) && k.Name.IndexOf(model.name, StringComparison.InvariantCultureIgnoreCase) > -1
更新:

从我在您的评论中了解到的情况来看,您可能正在寻找一种反射解决方案,您只需传递属性名称和模型

以下是一个例子:

public static class LinqExtension
{
    public static IEnumerable<T> WhereContains<T>(this IEnumerable<T> source, string propertyName, string model)
    {
        if(string.IsNullOrEmpty(propertyName)) { throw new ArgumentNullException(nameof(propertyName)); }

        if (string.IsNullOrEmpty(model)) { throw new ArgumentNullException(nameof(model)); }

        foreach (var item in source)
        {
            var property = item.GetType().GetProperty(propertyName);

            if (property == null)
            {
                throw new ArgumentNullException(nameof(property));
            }

            var value = property.GetValue(item, null)?.ToString();

            if (!string.IsNullOrEmpty(value) || value.IndexOf(model, StringComparison.InvariantCultureIgnoreCase) > -1)
            {
                yield return item;
            }
        }
    }
}

我希望这就是你要找的

首先,您不需要空检查,因为语句已转换为SQL。第二个谓词忽略SQL中的NOTNULL字符串。其次,您可能不需要
ToLower
调用(这会降低性能),因为使用了数据库排序规则,在大多数情况下,它是不区分大小写的。这留下了一个简短的谓词,可能不值得推广。如果你还想要的话,网上有很多这样做的例子。将
Func
替换为
Expression
@JeremyLakeman在我的问题中,使用
表达式将重用整个表达式,而不是特定属性上该表达式中的特定函数。EF Core只能翻译表达式,或对已知函数的调用。它无法使用它无法识别的
Func
执行任何操作。您的
包含
lambda不可能转换为sql。我的意思是“第二个谓词忽略sql中的空字符串”。首先,您不需要空检查,因为该语句已转换为sql。第二个谓词忽略SQL中的NOTNULL字符串。其次,您可能不需要
ToLower
调用(这会降低性能),因为使用了数据库排序规则,在大多数情况下,它是不区分大小写的。这留下了一个简短的谓词,可能不值得推广。如果你还想要的话,网上有很多这样做的例子。将
Func
替换为
Expression
@JeremyLakeman在我的问题中,使用
表达式将重用整个表达式,而不是特定属性上该表达式中的特定函数。EF Core只能翻译表达式,或对已知函数的调用。它无法使用它无法识别的
Func
执行任何操作。您的
包含
lambda不可能转换为sql。我的意思是“第二个谓词忽略sql中的空字符串”。这将让我在开始时定义实体类,这是我的问题。主要关注的是在特定属性上重用函数,而不是在静态属性上重用整个表达式entity@AliKleit因此您有多个具有相同属性的实体
名称
?您希望自动执行哪些操作,以便只能将
model.name
传递给它?是吗?事实上不是,让我们假设对于任何具有字符串数据类型的实体。因此,它可以在该数据类型上重用…这将让我定义实体类,这在一开始是我的问题。主要关注的是在特定属性上重用函数,而不是在静态属性上重用整个表达式entity@AliKleit因此您有多个具有相同属性的实体
名称
?您希望自动执行哪些操作,以便只能将
model.name
传递给它?是吗?事实上不是,让我们假设对于任何具有字符串数据类型的实体。所以它可以在该数据类型上重用。。。