5

首先考虑使用实体框架代码构建的具有多个表的数据库。每个表都包含不同类型的对象,但为了可扩展性,我希望创建一个通用查询构建器类。就这个类的框架而言,我有一个泛型类,旨在充当 Linq to SQL 的包装器:

public class DBQuerier<T>
    where T : class
{
    DbSet<T> relation;

    public DBQuerier(DbSet<T> table)
    {
        relation = table;
    }

    public bool Exists(T toCheck);
    public void Add(T toAdd);
    public T (Get Dictionary<String, Object> fields);
    public bool SubmitChanges();
    public void Update(T toUpdate, Dictionary<String, Object> fields);
    public void Delete(T toDelete);
}

当我尝试检查是否存在记录时,我的问题出现在第一个障碍,因为我无法在泛型类型 T 和我正在尝试使用的对象类型之间进行转换。如果我使用基本 Linq:

public bool Exists(T toCheck)
{
    return (from row in relation
        where row.Equals(toCheck)
        select row).Any();
}

即使我实现IComparable并指定了自己的 Equals 来比较单个字段,SQL 也只能处理原始类型,因此会发生运行时异常。Lambda 表达式似乎更接近了,但随后我再次遇到 SQL 无法处理原始类型以外的问题,尽管我的理解是这Expression.Equal迫使它使用类的可比较函数:

public bool Exists(T toCheck)
{
    ParameterExpression T1 = Expression.Parameter(typeof(myType), "T1");
    ParameterExpression T2 = Expression.Parameter(typeof(myType), "T2");
    BinaryExpression compare = Expression.Equal(T1, T2);
    Func<T, T, bool> checker =
        Expression.Lambda<Func<T, T, bool>>
            (compare, new ParameterExpression[] { T1, T2 }).Compile();
    return relation.Where(r => checker.Invoke(r, toCheck)).Any();
}

表达式树的设计是为了以后我可以添加一个 switch 语句来根据我试图查看的类型构建查询。我的问题是:有没有更简单/更好的方法来做到这一点(或修复我迄今为止尝试过的),因为我能看到的唯一其他选择是为每个表编写一个类(不那么容易扩展)或检查每个记录应用程序端(如果您必须传输整个数据库,可能会非常慢!)?如果我犯了非常基本的错误,我深表歉意,因为我已经很长时间没有处理这些问题了,在此先感谢!

4

3 回答 3

6

不要编译它。Func<T,bool>意味着“在内存中运行它”,而Expression<Func<T,bool>>意味着“保持这个谓词是什么的逻辑概念”,它允许像实体框架这样的框架将其转换为查询。

作为旁注,我认为实体框架不允许您a.Equals(b)进行查询,因此您必须这样做a.Id == b.Id

于 2013-08-05T16:42:24.753 回答
2

实体框架不太可能与您的自定义 linq 一起使用,它支持的命令非常严格。我要啰嗦一下,它是伪代码,但我找到了两个对我有用的解决方案。

我首先使用泛型方法,我的泛型数据库搜索器将接受 aFunc<T, string> nameProperty来访问我要查询的名称。EF 有许多用于访问集合和属性的重载,因此我可以通过传入c => c.CatName并使用它以通用方式访问属性来完成这项工作。虽然有点乱,所以:

后来我将其重构为使用接口。

我有一个函数可以对您传递给该方法的任何表/列执行文本搜索。

我创建了一个名为的接口INameSearchable,它只包含一个属性,该属性将成为要搜索的名称属性。然后我扩展了我的实体对象(它们是部分类)来实现INameSearchable. 所以我有一个名为的实体Cat,它有一个CatName属性。我使用接口return CatName;作为接口的 Name 属性。

然后我可以创建一个通用的 Search 方法where T : INameSearchable,它将公开Name我的接口公开的属性。然后我只是在我的方法中使用它来执行查询,例如。(内存中的伪代码!)

doSearch(myContext.Cats);

并且在方法中

public IEnumerable<T> DoSearch<T>(IDbSet<T> mySet, string catName)
{
   return mySet.Where(c => c.Name == catName);
}

非常漂亮,它允许我一般地搜索任何东西。

我希望这有帮助。

于 2013-08-05T17:18:09.903 回答
0

如果要使用 EntityFramework,则必须使用原始类型。原因是您的 LINQ 表达式被转换为 SQL 语句。SQL 对对象、IComparables、...一无所知。

如果您不需要它在 SQL 中,您首先必须对 SQL 执行查询,然后在内存中对其进行过滤。您可以使用当前使用的方法来做到这一点

于 2013-08-05T16:46:35.547 回答