Mar*_*175 5 c# linq entity-framework
考虑首先使用Entity Framework代码构建多个表的数据库.每个表都包含不同类型的对象,但我希望为了可扩展性而创建一个通用查询构建器类.到目前为止,这个类的框架我有一个泛型类,因此它可以作为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);
}
Run Code Online (Sandbox Code Playgroud)
我的问题来自第一个障碍,当我试图检查是否存在记录,因为我无法在泛型类型T和我正在尝试使用的对象类型之间进行转换.如果我使用基地Linq:
public bool Exists(T toCheck)
{
return (from row in relation
where row.Equals(toCheck)
select row).Any();
}
Run Code Online (Sandbox Code Playgroud)
发生运行时异常,因为即使我实现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();
}
Run Code Online (Sandbox Code Playgroud)
设计表达式树是为了以后我可以根据我试图查看的类型添加一个switch语句来构建查询.我的问题是:有没有更简单/更好的方法来做到这一点(或修复我迄今为止尝试过的),因为我能看到的唯一其他选项是为每个表编写一个类(不太容易扩展)或检查每个记录应用程序端(如果你必须转移整个数据库,可能会非常慢!)?如果我犯了这么非常基本的错误,我很抱歉,因为我已经很长时间没有这么做了,所以提前感谢!
不要编译它.Func<T,bool>
意味着"在内存中运行它",Expression<Func<T,bool>>
意思是"保持这个谓词是什么的逻辑思想",这允许像实体框架这样的框架将其转换为查询.
作为旁注,我认为实体框架不允许您a.Equals(b)
进行查询,因此您必须这样做a.Id == b.Id
实体框架不太可能与您的自定义 linq 一起使用,它支持的命令非常严格。我要闲聊一下,它是伪代码,但我找到了两个适合我的解决方案。
我首先使用泛型方法,我的通用数据库搜索器将接受 aFunc<T, string> nameProperty
来访问我要查询的名称。EF 有许多用于访问集和属性的重载,因此我可以通过传入c => c.CatName
并使用它以通用方式访问属性来完成这项工作。不过有点乱,所以:
后来我将其重构为使用接口。
我有一个函数可以对您传递给该方法的任何表/列执行文本搜索。
我创建了一个名为 的接口INameSearchable
,它只包含一个属性,该属性将成为要搜索的名称属性。然后我扩展了我的实体对象(它们是部分类)来实现INameSearchable
. 所以我有一个名为的实体Cat
,它有一个CatName
属性。我使用该接口return CatName;
作为接口的 Name 属性。
然后,我可以创建一个通用搜索方法where T : INameSearchable
,它将公开Name
我的界面公开的属性。然后,我只需在我的方法中使用它来执行查询,例如。(记忆中的伪代码!)
doSearch(myContext.Cats);
并在方法中
public IEnumerable<T> DoSearch<T>(IDbSet<T> mySet, string catName)
{
return mySet.Where(c => c.Name == catName);
}
Run Code Online (Sandbox Code Playgroud)
而且非常漂亮的是,它允许我一般性地搜索任何东西。
我希望这有帮助。