【发布时间】:2016-11-02 23:43:28
【问题描述】:
(已编辑)我正在使用文档表和文档三元组表来试验 EF 核心。每个文档可以包含 0 个或多个 (RDF) 三元组,由谓词加对象表示。
对应的EF实体是:
public sealed class Document
{
public string Id { get; set; }
public string CreatorId { get; set; }
public string CategoryId { get; set; }
public string Title { get; set; }
public string Author { get; set; }
// ...
public IList<DocumentTriple> DocumentTriples { get; set; }
}
和:
public sealed class DocumentTriple
{
public int Id { get; set; }
public string DocumentId { get; set; }
public string Predicate { get; set; }
public string Object { get; set; }
public Document Document { get; set; }
}
他们的 SQL 定义:
CREATE TABLE [dbo].[Document](
[Id] [varchar](32) NOT NULL,
[CreatorId] [varchar](50) NOT NULL,
[CategoryId] [varchar](20) NOT NULL,
[Title] [nvarchar](500) NOT NULL,
[Author] [nvarchar](500) NOT NULL,
/* ... */
CONSTRAINT [PK_dbo.Document] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[DocumentTriple](
[Id] [int] IDENTITY(1,1) NOT NULL,
[DocumentId] [varchar](32) NOT NULL,
[Predicate] [varchar](100) NOT NULL,
[Object] [nvarchar](1000) NOT NULL,
CONSTRAINT [PK_DocumentTriple] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[DocumentTriple] WITH CHECK ADD CONSTRAINT [FK_dbo.DocumentTriple_dbo.Document_DocumentId] FOREIGN KEY([DocumentId])
REFERENCES [dbo].[Document] ([Id])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[DocumentTriple] CHECK CONSTRAINT [FK_dbo.DocumentTriple_dbo.Document_DocumentId]
GO
现在,我想对文档应用一些可变过滤器,使用这种模式:我首先创建一个 IQueryable documents 对象,包括三元组,然后添加越来越多的过滤器,例如 @987654326 @。
其中一个过滤器是Tuple 的列表,其中 1 = 谓词过滤器值和 2=null 或对象过滤器值。我只想获取那些三元组中的任何一个至少匹配一个过滤谓词或谓词/值对的文档。
在 SQL 中,我可以这样做:
select * from document
inner join documenttriple on documenttriple.documentid=document.id
where (documenttriple.[predicate]='somepredicate' and documenttriple.[object]='someobject')
or (documenttriple.[predicate]='somepredicate')
如何在 EF 代码中执行此操作?我试过了:
documents = from d in documents
join dt in db.DocumentTriples on d.Id equals dt.DocumentId
where filter.Triples.Any(t => t.Item1 == dt.Predicate &&
(t.Item2 == null || t.Item2 == dt.Object))
select d;
但这似乎并没有过滤三元组。
编辑
我尝试使用更多代码示例更好地解释自己。这是我的(缩短的)代码:
private IQueryable<Document> ApplyDocumentFilters(IQueryable<Document> documents,
DocumentFilter filter)
{
if (!String.IsNullOrEmpty(filter.CreatorId))
documents = documents.Where(d => d.CreatorId == filter.CreatorId);
if (!String.IsNullOrEmpty(filter.CategoryId))
documents = documents.Where(d => d.CategoryId == filter.CategoryId);
if (!String.IsNullOrEmpty(filter.Title))
documents = documents.Where(d => d.Title.Contains(filter.Title));
// ...and so forth for all the filter properties...
// here I want to filter only the documents which have at least 1 of their triples
// matching any of the filter's triples. DOES NOT WORK
if (filter.Triples.Count > 0)
{
documents = from d in documents
join dt in db.DocumentTriples on d.Id equals dt.DocumentId
where filter.Triples.Any(t => t.Item1 == dt.Predicate &&
(t.Item2 == null || t.Item2 == dt.Object))
select d;
}
return documents;
}
public PagedData<Document> GetDocuments(DocumentFilter filter)
{
if (filter == null) throw new ArgumentNullException(nameof(filter));
using (CatalogContext db = new CatalogContext(_options))
{
IQueryable<Document> documents = db.Documents
.Include(d => d.DocumentTriples)
.AsNoTracking().AsQueryable();
documents = ApplyDocumentFilters(documents, filter);
int total = documents.Count();
documents = documents.OrderBy(d => d.Title).ThenBy(d => d.PublicationYear);
return new PagedData<Document>(total,
documents.Skip((filter.PageNumber - 1) * filter.PageSize).Take(filter.PageSize).ToList());
}
}
如您所见,我收到一个过滤器对象,其中包含我要应用的所有过滤器,然后按属性构建 IQueryable 属性。至于三元组,我希望所有文档至少有 1 个与过滤器的任何三元组匹配的三元组。
【问题讨论】:
标签: c# entity-framework .net-core