sebastienros / yessql

A .NET document database working on any RDBMS
MIT License
1.17k stars 195 forks source link

How to get document (in separate transaction) after QueryIndex #538

Open ovekaaven opened 3 months ago

ovekaaven commented 3 months ago

I have an index, and I want a background job to go through each document one by one and process each in a separate transaction. Thus, Query is not useful since it would not use the transaction I want, but I can't quite see how to get DocumentId from the QueryIndex result, either. I'm trying to do something like

var query = await session.QueryIndex<JobIndex>(x => x.Pending).ListAsync();
foreach (var index in query) {
    await session.BeginTransactionAsync();
    var job = session.GetAsync<Job>(index.DocumentId);
    // do stuff
    await session.CommitAsync();
}

Is this possible? The "Id" field in the MapIndex class seems to be unrelated to the document ID.

sebastienros commented 2 months ago

We could probably add DocumentId to IIndex and then also populate it when doing index queries since it's in the table.

In the meantime you can create your own SQL query to list this index. Then to have distinct transactions you can create a new session each time. The other option is to call session.SaveChangesAsync which will dispose the transaction, so the next call to BeginTransactionAsync will create a new one (and open a new connection, pooled though).

ovekaaven commented 2 months ago

Indeed, having the DocumentId available right away would be great. I've since come up with a relatively simple workaround, costing a redundant join but no custom stuff needed, so works for me until a proper solution exists:

var job = await session.Query<Job, JobIndex>(x => x.Id == index.Id).FirstOrDefaultAsync();

Another problem I discovered with this, is that if you ever abort the inner transaction with CancelAsync, you set a flag which is never cleared, not even by BeginTransactionAsync, the session object is simply unusable afterwards. Which essentially means you have to create a new session object for every transaction (and since I have to use DI, it means I have to create a new DI scope for every transaction). I suppose that's probably not an unreasonable thing to need to do, I just wish it was documented or something.

Thanks for the help so far!

sebastienros commented 2 months ago

Another option would be for you to add this document id to the concrete index. Like any other value. In Orchard we do that to point to the document using a logical id, a unique identifier that is constant to the lifetime of the document (content item id) since the DocumentId will vary for each new version of the same document.