我有一个类似于以下内容的界面:
public IEnumerable<IDocument> Search(Predicate<IDocument> predicate) { ... }
IDocument看起来像这样:
public interface IDocument
{
string Id {get; set;}
string Title {get; set;}
...
}
我即将实现一个文档提供程序,我必须分解Predicate的内容并提取属性,以便为我们当前没有OR / M映射的文档数据库创建一个SQL字符串。例如:我想知道用户是按ID还是按标题搜索,因此我知道是否可以按ID搜索或者必须在标题上执行LIKE搜索。
我一直在大量使用LINQ,但这是我第一次坐在管道的另一端......我已经阅读了一些关于表达式树和反射的内容,但这些内容并没有落入还有。如何(如果?)我可以分解/反映谓词,所以我得到一个参数列表,我可以将其汇总成一个SQL字符串?我正在寻找像这样粗略草图的东西:
public IEnumerable<IDocument> Search(Predicate<IDocument> predicate)
{
string id = DoSomeMagic(predicate, "Id");
string title = DoSomeMagic(predicate, "Title");
if (!string.isNullOrEmpty(id))
...make ID search
else
...search by title
}
免责声明:提供商是针对今年秋季更换的内部遗留系统,这使得内联SQL成为正确的选择; o)
答案 0 :(得分:3)
您不能使用谓词或委托来执行此操作。它们被编译,无法获得有关它的功能的信息。你真的需要Expression
树,但是自己解析这个可能很困难。你最好使用O / RM工具。
例如,当您将Expression与LINQ to SQL一起使用时,构建搜索方法将变得轻而易举:
public IEnumerable<Document> Search(
Expression<Func<Document, bool>> predicate)
{
using (db = new DocumentDataContext())
{
return db.Documents.Where(predicate).ToArray();
}
}
答案 1 :(得分:1)
你不能轻易地反省谓词。也许您应该考虑将您的设计更改为更具特色的谓词类型,更具体的谓词界面:
public interface IDocument
{
string Id {get; set;}
string Title {get; set;}
}
public class SearchCriteria
{
public Nullable<int> Id;
public string Title;
}
public IEnumerable<IDocument> Search(SearchCriteria predicate)
{
if (predicate.Id.HasValue)
//...make ID search
else if (!string.IsNullOrEmpty(predicate.Title))
//...search by title
else
// other kind of search
}
使用属性替换公共字段,将搜索逻辑放在SearchCriteria中(例如.GetResult()或.GetSQLQuery()),这可能适合您的系统,假设您可以了解所有可用的搜索条件。
答案 2 :(得分:0)
您需要将方法声明为接受表达式&gt;代替。这个表达式可以被反思(虽然它可以有很多不同的东西)。
尝试在LinqPad中运行以下命令(LinqPad提供了转储扩展方法,可以很好地显示表达式)
void Main()
{
show(x=>x.Length==5);
}
void show(Expression<Predicate<string>> e){
e.Dump();
}
您可以先调用Compile