2014-01-14 47 views
3

简体域名:QueryOver集合包含所有值

public class MasterDocument { 
    Guid ID; 
    Program StorageCompartment; 
    ISet<DocumentCompartment> Compartments; 
} 
public class Program { 
    int ID; 
    string GroupName; 
} 
public class DocumentCompartment { 
    int ID; 
    Program AssociatedCompartment; 
    MasterDocument AssociatedDocument; 
} 
public class Document { 
    Guid ID; 
    MasterDocument MasterDocument; 
    //Many more properties 
} 

我知道这有点令人费解,但存在这样的,因为我们已经通过把某些记录(如文件)为不同的处理安全问题的模式数据库对应于它们所属的程序/舱(可互换术语)。 MasterDocument,Program和DocumentCompartment的表位于“主”数据库中,其中包含所有隔离专区的信息,而几个不同的数据库则分别包含自己的Documents表。无论如何,在这个问题上:

我想构建一个查询,我传递了一个组名列表,并且我只想要那些没有包含在该组名列表中的关联隔离的文档。

作为一个例子:
文档1与隔室相关联的P1
文档2与P2,P3相关联,并且P7
文档3与P1相关联,并且P3
我想要查询针对组:P1,P3, P4,P7(这些是我获得许可的组)

我应该找回Doc1和Doc3,因为我没有P2权限,Doc2需要这个权限。我可以这样使用LINQ提供程序使用下面的查询做:

string[] groups = new[] { "P1", "P3", "P4", "P7" }; 
return Session.Query<Document>().Where(doc => doc.MasterDocument.Compartments.All(comp => groups.Contains(comp.AssociatedCompartment.GroupName)); 

(同样在上面记:如果我尝试封装在文档类是逻辑和方法传递给“去哪儿”方法,例如返回Session.Query()。其中​​(doc => doc.CanAccess(groups)),然后我得到一个System.NotSupportedException。我有点理解为什么,但如果有解决方法,这将是非常好的。

产生的生成的SQL是这样的:

exec sp_executesql 
N'select 
doc.DocumentGuid as guid 
from Documents doc 
where not (exists 
(select comp.DocumentCompartmentID 
from Master.MasterDocuments master, 
     Master.DocumentCompartments comp, 
     Master.Programs prog 
where doc.DocumentGuid=master.DocumentGuid and 
     master.DocumentGuid=comp.DocumentGuid and 
     comp.CompartmentID=prog.ProgramID and 
     not (prog.ADGroupName in ('P1', 'P3', 'P4', 'P7')) 
))', 

我现在TR要弄清楚如何使用NHibernate QueryOver语法来完成相同的查询。不幸的是,我没有足够的知识或经验知道如何编写它。任何帮助,将不胜感激!

回答

1

我相信你想是这样的:

IList<Guid> results = Session.QueryOver<Document>(() => documentAlias) 
    .WithSubquery.WhereNotExists(
     QueryOver.Of<MasterDocument>() 
       .Where(md => md.ID == documentAlias.MasterDocument.ID) // Not sure about this 
      .JoinQueryOver(md => md.Compartments) 
      .JoinQueryOver(cmp => cmp.AssociatedCompartment) 
       .WhereNot(acmp => acmp.GroupName.IsIn(new[] { "P1", "P3", "P4", "P7" }))) 
    .Select(doc => doc.ID) 
    .List<Guid>(); 

我不知道,如果MasterDocument.IDDocument.MasterDocument.ID之间的比较是正确的,我发表过评论,但这应该让你在正确的方向开始。

的几个注意事项:

  • 一般情况下,你不能使用LINQ的语法与QueryOver。他们看起来很相似,但他们是不同的查询技术。
  • 有关QueryOver的基本介绍,请查看nhibernate.info上的this guide。不幸的是,这与你在官方文档中可以得到的一样好。
  • 这假设你根据你所呈现的类的几个关于映射的东西。
+0

那么,*似乎*工作。我没有真正创建任何单元测试,以确保它做我想做的事情,但调用我的查询方法的单元测试至少现在不会在NHibernate代码中引发异常。 –

+0

Btw,你是否有可能在Document类中封装LINQ逻辑有任何评论,所以我可以这样调用它:Session.Query()。Where(doc => doc.CanAccess(groups))?我真正想要做的是拦截我们的查询,检查T是否是特定类型(例如ISecurable,它定义了bool CanAccess(...)),并插入表达式以仅当我可以访问'它。如上所述,内联逻辑起作用,但试图在方法内调用该逻辑不会。 –

+0

通常,您不能从QueryOver查询中调用实体的方法。将QueryOver视为直接转换为SQL。因此,'CanAccess'在SQL查询中没有意义。你将不得不水合实体和*然后*调用该方法。 –

相关问题