哪个ORM支持这个

Luk*_*101 5 c# sql orm

我有一个可选的查询部分需要在某种条件下执行.这是示例代码:

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是:

  • NHibernate的
  • LLBLGEN
  • 亚音速

我对任何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查询执行,因此 - 两个不同的查询计划:

  • 查询计划基于索引查找(非常快),如果全部== 0
  • 基于索引扫描的查询计划(非常慢),如果全部!= 0

所有== 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.


tt8*_*t83 9

这可以使用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)


Kev*_*ang 6

NHibernate使用Criteria API支持这一点:

ICriteria criteria = session.CreateCriteria<Article>();

if (cat > 0)
    criteria.Add(Expression.Eq("categoryID", cat));
Run Code Online (Sandbox Code Playgroud)


ito*_*son 2

您可能可以使用任何 LINQ 提供程序来执行此操作,但我知道LightSpeed ORM 支持它:

var query = UnitOfWork.Articles;
if (cat > 0)
  query = query.Where(a => a.CategoryId == cat);
Run Code Online (Sandbox Code Playgroud)