我有一个可选的查询部分需要在某种条件下执行.这是示例代码:
int cat = 1;
int UserID = 12;
string qry = "select * from articles";
if(cat > 0)
qry += " where categoryID = " + cat;
if(UserID > 0)
qry += " AND userid = " + UserID; //The AND may be a WHERE if first condition is false
Run Code Online (Sandbox Code Playgroud)
如您所见,我在查询中有一个if语句.我目前正在使用实体框架,它不支持这种情况.那里有ORM支持吗?
编辑 我试图假设查询.但我有大约20个"IF"语句,而且查询很长.
我看到的ORM是:
我对任何ORM持开放态度.谢谢
Ale*_*nin 10
正如此处已经提到的,LINQ允许通过简单地向其添加更多条件来扩展任何查询.
var query =
from x in xs
where x==1
select x;
if (mustAddCriteria1)
query =
from x in query
where ... // criteria 1
select x;
if (mustAddCriteria2)
query =
from x in query
where ... // criteria 2
select x;
Run Code Online (Sandbox Code Playgroud)
等等.这种方法非常完美.但很可能,您知道LINQ查询的编译非常昂贵:例如,Entity Framework每秒可以编译大约500个相对简单的查询(参见例如ORMBattle.NET).
另一方面,许多ORM工具支持编译查询:
IQueryable实例传递给某个Compile方法,并获得一个允许稍后更快执行它的委托,因为在这种情况下不会发生重新编译.但是如果我们尝试在这里使用这种方法,我们立即注意到我们的查询实际上是动态的:IQueryable我们执行的每次都可能与前一次不同.查询部分的存在由外部参数的值确定.
那么我们可以在没有例如显式缓存的情况下执行编译的查询吗?
DataObjects.Net 4支持所谓的"布尔分支"功能.它意味着在查询编译期间评估任何常量布尔表达式,并将其实际值作为真实布尔常量注入SQL查询(即不作为参数值或使用参数的表达式).
此功能允许轻松地依赖于此类布尔表达式的值生成不同的查询计划.例如这段代码:
int all = new Random().Next(2);
var query =
from c in Query<Customer>.All
where all!=0 || c.Id=="ALFKI"
select c;
Run Code Online (Sandbox Code Playgroud)
将使用两个不同的SQL查询执行,因此 - 两个不同的查询计划:
所有== null,SQL查询的情况:
SELECT
[a].[CustomerId],
111 AS [TypeId] ,
[a].[CompanyName]
FROM
[dbo].[Customers] [a]
WHERE(( CAST( 0 AS bit ) <> 0 ) OR( [a].[CustomerId] = 'ALFKI' ) );
Run Code Online (Sandbox Code Playgroud)
所有== null,查询计划的情况:
|--Compute Scalar(DEFINE:([Expr1002]=(111)))
|--Clustered Index Seek(OBJECT:([DO40-Tests].[dbo].[Customers].[PK_Customer] AS [a]), SEEK:([a].[CustomerId]=N'ALFKI') ORDERED FORWARD)
Run Code Online (Sandbox Code Playgroud)
第二种情况(全部!= null),SQL查询:
SELECT
[a].[CustomerId],
111 AS [TypeId] ,
[a].[CompanyName]
FROM
[dbo].[Customers] [a]
WHERE(( CAST( 1 AS bit ) <> 0 ) OR( [a].[CustomerId] = 'ALFKI' ) );
-- Notice the ^ value is changed!
Run Code Online (Sandbox Code Playgroud)
第二种情况(全部!= null),查询计划:
|--Compute Scalar(DEFINE:([Expr1002]=(111)))
|--Clustered Index Scan(OBJECT:([DO40-Tests].[dbo].[Customers].[PK_Customer] AS [a]))
-- There is index scan instead of index seek!
Run Code Online (Sandbox Code Playgroud)
请注意,几乎任何其他ORM都会使用整数参数将其编译为查询:
SELECT
[a].[CustomerId],
111 AS [TypeId] ,
[a].[CompanyName]
FROM
[dbo].[Customers] [a]
WHERE(( @p <> 0 ) OR ( [a].[CustomerId] = 'ALFKI' ) );
-- ^^ parameter is used here
Run Code Online (Sandbox Code Playgroud)
由于SQL Server(以及大多数数据库)为特定查询生成单个版本的查询计划,因此在这种情况下它只有一个选项 - 生成带索引扫描的计划:
|--Compute Scalar(DEFINE:([Expr1002]=(111)))
|--Clustered Index Scan(OBJECT:([DO40-Tests].[dbo].[Customers].[PK_Customer] AS [a]), WHERE:(CONVERT(bit,[@p],0)<>(0) OR [DO40-Tests].[dbo].[Customers].[CustomerId] as [a].[CustomerId]=N'ALFKI'))
Run Code Online (Sandbox Code Playgroud)
好的,这是对此功能有用性的"快速"解释.让我们现在回到你的案子.
布尔分支允许以非常简单的方式实现它:
var categoryId = 1;
var userId = 1;
var query =
from product in Query<Product>.All
let skipCategoryCriteria = !(categoryId > 0)
let skipUserCriteria = !(userId > 0)
where skipCategoryCriteria ? true : product.Category.Id==categoryId
where skipUserCriteria ? true :
(
from order in Query<Order>.All
from detail in order.OrderDetails
where detail.Product==product
select true
).Any()
select product;
Run Code Online (Sandbox Code Playgroud)
这个例子与你的不同,但它说明了这个想法.我主要使用不同的模型来测试这个(我的例子是基于Northwind模型).
此查询是:
Query.Execute(...)方法以将其作为编译查询执行.IQueryable.这可以使用linq to sql来完成...
IQueryable<Article> query = yourDataContext.Articles;
if (catId > 0)
query = query.Where(x => x.CategoryId == catId);
return query.ToList();
Run Code Online (Sandbox Code Playgroud)
NHibernate使用Criteria API支持这一点:
ICriteria criteria = session.CreateCriteria<Article>();
if (cat > 0)
criteria.Add(Expression.Eq("categoryID", cat));
Run Code Online (Sandbox Code Playgroud)
您可能可以使用任何 LINQ 提供程序来执行此操作,但我知道LightSpeed ORM 支持它:
var query = UnitOfWork.Articles;
if (cat > 0)
query = query.Where(a => a.CategoryId == cat);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
911 次 |
| 最近记录: |