我可以使以下IQueryable linq语句通用

Nei*_*eil 3 c# generics entity-framework linq-to-sql

有没有办法让以下数据库查询构建器通用?

private IQueryable<Foo> ByName(IQueryable<Foo> dbQuery, Query query)
{
    string[] searchTerms = query.Data.Replace(" ","").ToLower().Split(',');

    if (query.Exclude)
    {
        return dbQuery.Where(x => searchTerms.All(
            y => y != x.Name.Replace(" ", "").ToLower()));
    }

    return dbQuery.Where(x => searchTerms.Any(
        y => y == x.Name.Replace(" ", "").ToLower()));
}
Run Code Online (Sandbox Code Playgroud)

我对Foo的许多不同属性都有相同的功能.ByCounty,ByTown,ByStreet等

我已经编写了一些返回linq的函数,如下所示

public Expression<Func<Foo, bool>> FoosAreWithinDistanceFromGeocode(
    double distance, Geocode geocode)
{
    double distanceSquare = distance * distance;
    return foo => ( SqlFunctions.Square((double)(
        foo.Address.Geocode.Easting - geocode.Easting)) +
        SqlFunctions.Square((double)(fooAddress.Geocode.Northing - 
        geocode.Northing)) ) <= distanceSquare;
}
Run Code Online (Sandbox Code Playgroud)

但我似乎无法找到Linq-to-SQL的东西是否不能使用泛型,或者是否可以将属性作为泛型和类似的东西传递.


编辑:我一般都在为一个搜索词工作.

Where [query.Data == "Foo1"]

return dbQuery.Where(SearchMatch("Name", query.Data));

public Expression<Func<Foo, bool>> SearchMatch(string propertyName, string searchTerm)
{
    var foo = Expression.Parameter(typeof(Foo), "foo");
    var prop = Expression.Property(foo, propertyName);
    var search = Expression.Constant(searchTerm);
    var equal = Expression.Equal(prop, search);

    return Expression.Lambda<Func<Foo, bool>>(equal, foo);
}
Run Code Online (Sandbox Code Playgroud)

任何人有任何想法如何使它适用于一系列字符串?

cas*_*One 5

您需要定义一个公开您要访问的属性的接口,如下所示:

public interface IHaveName
{
    string Name { get; }
}
Run Code Online (Sandbox Code Playgroud)

然后,在您的类上,您将实现该接口:

public class Foo : IHaveName
Run Code Online (Sandbox Code Playgroud)

如果您正在使用从DBML文件生成的类,则这些类将使用partial关键字标记,因此实现该接口就像创建新文件一样简单,并插入:

public partial class Foo : IHaveName
Run Code Online (Sandbox Code Playgroud)

由于该属性已在.dbml文件生成的其他 .cs文件中声明为public,因此该接口是隐式实现的.

最后,您将重写您的ByName方法以获取具有实现您的接口的约束的泛型类型参数IHaveName:

private IQueryable<T> ByName<T>(IQueryable<T> dbQuery, Query query)
    where T : IHaveName
{
    // Everything else is the same.
Run Code Online (Sandbox Code Playgroud)

对于您的其他属性(以及使用它们的方法),您可以将它们聚合到一个界面中,或根据您的需要将它们分开.


根据您的编辑,如果要动态创建表达式,则不必放弃编译时安全性:

public Expression<Func<Foo, bool>> SearchMatch(
    Expression<Func<Foo, string>> property, string searchTerm)
{
    var foo = Expression.Parameter(typeof(Foo), "foo");
    // Get the property info from the property expression.
    var prop = Expression.Property(foo, 
        (property.Body as MemberExpression).Member as PropertyInfo);
    var search = Expression.Constant(searchTerm);
    var equal = Expression.Equal(prop, search);

    return Expression.Lambda<Func<Foo, bool>>(equal, foo);
}
Run Code Online (Sandbox Code Playgroud)

然后你这样打电话:

var expression = SearchMatch(f => f.Name, "searchTerm");
Run Code Online (Sandbox Code Playgroud)

这可确保您传递给的属性SearchMatch实际存在Foo.请注意,如果要为其他标量属性类型创建此泛型,请执行以下操作:

public Expression<Func<Foo, bool>> SearchMatch<T>(
    Expression<Func<Foo, T>> property, T searchTerm)
{
    var foo = Expression.Parameter(typeof(Foo), "foo");
    // Get the property info from the property expression.
    var prop = Expression.Property(foo, 
        (property.Body as MemberExpression).Member as PropertyInfo);
    var search = Expression.Constant(searchTerm);
    var equal = Expression.Equal(prop, search);

    return Expression.Lambda<Func<Foo, bool>>(equal, foo);
}
Run Code Online (Sandbox Code Playgroud)