(EDITED)ドキュメントのテーブルとドキュメントのトリプルテーブルを使ってEFコアを試しています。各文書には、述語とオブジェクトで表される0以上の(RDF)トリプルを含めることができます。EFコア:リスト内の項目に一致するフィルタレコード
対応する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
objecを作成します。 t(トリプルを含む)を入力し、documents = documents.Where(...)
のようなフィルタを追加します。
これらのフィルタの1つは、Tuple
のリストです。ここで、1は述語のフィルタ値、2はnullまたはobjectのフィルタ値です。私は少なくとも1つのフィルタ述語または述語/値のペアと一致するトリプルのいずれかを持つドキュメントのみを取得したいと思います。
select * from document
inner join documenttriple on documenttriple.documentid=document.id
where (documenttriple.[predicate]='somepredicate' and documenttriple.[object]='someobject')
or (documenttriple.[predicate]='somepredicate')
がどのように私はEFコードでこれを行うことができます:SQLで
、私はこのような何かをするだろうか?私は試みました:
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;
しかし、これはトリプルをフィルタリングしていないようです。私はより良いより多くのコードサンプルを使用して自分自身を説明しようと
EDIT
。ここに私の(短縮)コードです:あなたが見ることができるように
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プロパティを構築します。トリプルについては、フィルタのトリプルのANYに一致する少なくとも1つのトリプルを持つすべてのドキュメントを取得したい。
私は自分自身をうまく説明していないと悪いですが、フィルタを表すタプルの配列があり、同じIQueryable上の条件がますます連結されています。 SQLサンプルはフィルタリングのタイプを示すことを意図していました。私のシナリオではコードが配列を取得し、その中のタプルのいずれかと一致するだけで十分です。結局、私はIQueryableを持っていなければなりません。 db.Documents.Include(d => d.DocumentTriples).AsNoTracking()。AsQueryable()から、いくつかのフィルタを追加し、ソートとページングで終了します。 –
Naftis
私はまだこれについて混乱していますが、問題を正しく理解していれば、更新された回答に追加することができます。 – Transcendent
具体的なコードを追加して質問を編集しました。これは私の質問を明確にするはずです。ありがとうございました – Naftis