将WHERE子句从LINQ拉到SQL
我正在与想要将LINQ to SQL与其内部DAL混合使用的客户端。最终他们希望能够使用典型的LINQ语法来查询他们的图层。这变得棘手的一点是,他们动态地构建他们的查询。因此,最终我想要的是能够采用LINQ查询,将其分开并能够检查这些作品以将正确的对象拉出来,但我并不想真正想要翻译“where”表达式到SQL中。这是我可以使用微软代码生成的东西吗?还是有更简单的方法来做到这一点?将WHERE子句从LINQ拉到SQL
(你的意思是LINQ,没有真正LINQ到SQL)
当然,你可以做到这一点 - 但它是大量大量的工作。 Here's how;我建议“不要”。您也可以查看DbLinq的源代码 - 了解他们是如何做到的。
如果只是想Where
,这是一个更容易一点 - 但只要你开始连接,分组等 - 这将是非常很难做到。
这里的只是Where
支持的自定义LINQ FPGA实现(不完全可查询的供应商,但足够用Where
努力让LINQ):
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace YourLibrary
{
public static class MyLinq
{
public static IEnumerable<T> Where<T>(
this IMyDal<T> dal,
Expression<Func<T, bool>> predicate)
{
BinaryExpression be = predicate.Body as BinaryExpression;
var me = be.Left as MemberExpression;
if(me == null) throw new InvalidOperationException("don't be silly");
if(me.Expression != predicate.Parameters[0]) throw new InvalidOperationException("direct properties only, please!");
string member = me.Member.Name;
object value;
switch (be.Right.NodeType)
{
case ExpressionType.Constant:
value = ((ConstantExpression)be.Right).Value;
break;
case ExpressionType.MemberAccess:
var constMemberAccess = ((MemberExpression)be.Right);
var capture = ((ConstantExpression)constMemberAccess.Expression).Value;
switch (constMemberAccess.Member.MemberType)
{
case MemberTypes.Field:
value = ((FieldInfo)constMemberAccess.Member).GetValue(capture);
break;
case MemberTypes.Property:
value = ((PropertyInfo)constMemberAccess.Member).GetValue(capture, null);
break;
default:
throw new InvalidOperationException("simple captures only, please");
}
break;
default:
throw new InvalidOperationException("more complexity");
}
return dal.Find(member, value);
}
}
public interface IMyDal<T>
{
IEnumerable<T> Find(string member, object value);
}
}
namespace MyCode
{
using YourLibrary;
static class Program
{
class Customer {
public string Name { get; set; }
public int Id { get; set; }
}
class CustomerDal : IMyDal<Customer>
{
public IEnumerable<Customer> Find(string member, object value)
{
Console.WriteLine("Your code here: " + member + " = " + value);
return new Customer[0];
}
}
static void Main()
{
var dal = new CustomerDal();
var qry = from cust in dal
where cust.Name == "abc"
select cust;
int id = int.Parse("123");
var qry2 = from cust in dal
where cust.Id == id // capture
select cust;
}
}
}
我只是想去的地方。我同意分组和连接超出范围,公司也不希望以这种方式使用数据。它们将完整的对象从数据库中拉出来非常庞大。所以,最后我希望它是像类别中CompanyDal.Categories IEnumerable的
行;那么我会添加一个能够做到这一点的例子。 – 2009-11-30 22:37:59
我刚刚阅读了关于表达式树的一篇有趣的文章,LINQ to SQL使用它们将查询翻译成SQL并通过网络发送。
也许这是你可以使用的东西?
从技术上讲,如果你的DAL公开IQueryable<T>
而不是IEnumerable<T>
,您也可以实施IQueryProvider并按照您的描述进行操作。但是,这并不是因为内心的淡淡。
但是,如果您在DAL中公开自己的LINQ to SQL表,他们会为您做这件事。尽管你会处理客户端代码对如何表达SQL查询的控制权,但是通常会产生一个(很大的)风险,而通常的结果是一些复杂的查询,它将所有内容连接在一起并将分页打成一个顶点,性能。
我认为你应该仔细考虑什么是实际上需要从DAL和只公开。
只是一些虽然。我知道一些语言支持构建了一个可以在代码本身中执行的字符串。我从来没有用.Net来尝试过,但这在LISP等函数式语言中很常见。既然.Net支持lambda,也许这是可能的。 由于F#即将推出.Net,如果现在不是这样,也许可能会有这种可能。
我想说的是,如果你能做到这一点,那么也许你可以建立一个字符串,将用作LINQ语句,然后执行它。由于它是一个字符串,因此可以分析字符串并获取所需的信息。
给那里有同样问题的人。从LINQ到SQL中提取where子句并不是那么直截了当,正如人们所希望的那样。另外,这样做本身可能是没有意义的。根据需求,有几个选项 - 要么从生成的字符串中抓取它,但它将包含参数引用和对象属性映射,这些映射也必须解析,因此这些也必须从原创提供商,否则这将是毫无意义的。另一种方法是找到一个可以实现这一点的模块化提供程序,并且可以方便地访问成员映射,但是,如果没有查询的其余部分,我再次发现实用程序功能不大,因为where子句将引用表/ select语句中的列别名。
我有一个类似的任务,在几年前为自定义ORM/DAL编写一个完整的提供者。虽然它是我工作过的最复杂的事情,但作为一名体验开发人员,我可以说这不是一件坏事,因为有些人一旦将自己的头脑置于这种组件基础的概念之后就会声称。我所看到的一些解决方案的方式错误,添加了多余的功能,并有额外的代码解决底层逻辑引入的问题。例如。 “优化”阶段/模块尝试重新分析由主解析器生成的臃肿的嵌套SQL。如果后者的设计方式可以从一开始就输出干净的SQL,那么就不需要清理阶段。我见过提供商为每个位置创建一个新的嵌套级别并加入呼叫。这是一个糟糕的策略。通过将查询分解为三个/四个主要部分 - 选择,从哪里和orderby(哪些是在树正在访问时单独构建的),完全避免了这个问题。我已经开发了一个基于这些原则为自定义ORM/DAL提供的对象到数据(又名LINQ到SQL),它生成漂亮,干净的SQL,并具有出色的性能,因为每条语句都编译为IL和缓存。
对于任何想要做类似事情的人,请查看我的帖子,其中包含一个带有教程/准系统实施的示例项目,可以轻松了解它的工作原理。包括也是完整的解决方案:
新增例如根据注释 – 2009-11-30 22:57:41