i am working on a Winui/c# app with EF core and sqlite db.
i am searching in a db with multiple tables every tables contains 9M records (9,000,000).
for this heavy search i used Task.Run and async/await. now there is an issue, when i search for a data i can see that app is working fine and result is shown.
but if i do another search i get some exception:
Exception thrown: ‘System.InvalidOperationException’ in WinRT.Runtime.dll
Exception thrown: ‘System.ArgumentOutOfRangeException’ in WinRT.Runtime.dll
i puted all codes into Dispatcher.TryEnqueue and issue fixed, however Task.Run does not have any effect and ui is blocking.
so how i can fix this? it seems that db can not work properly in Task.Run
await Task.Run(async () =>
{
await PerformSearchAsync(query, progress, cancellationTokenSource.Token);
});
private Dictionary<TableType, Func<DbContext, IQueryable<object>>> tableMappings = new Dictionary<TableType, Func<DbContext, IQueryable<object>>>
{
{ TableType.T935, db => db.Set<Person935>() },
{ TableType.T936, db => db.Set<Person936>() },
{ TableType.T937, db => db.Set<Person937>() },
{ TableType.T938, db => db.Set<Person938>() },
{ TableType.T939, db => db.Set<Person939>() },
{ TableType.T93033, db => db.Set<Person93033>() }
};
public async Task PerformSearchAsync(string query, IProgress<int> progress, CancellationToken cancellationToken)
{
var db = new IFDBDbContext();
var tableQueries = new List<IAsyncEnumerable<object>>();
var tableType = GetTableType(SearchQuery);
if (tableMappings.TryGetValue(tableType, out var dbQuery))
{
var dbSet = dbQuery(db);
tableQueries.Add(GetSearchResultsAsync(dbSet, query, cancellationToken));
}
// Track progress
int totalTables = tableQueries.Count;
int completedTables = 0;
int completedItems = 0;
foreach (var tableQuery in tableQueries)
{
await foreach (var item in tableQuery.WithCancellation(cancellationToken))
{
completedItems++;
dispatcherQueue.TryEnqueue(() =>
{
DataList.Add(item);
_tmpCompletedItems = completedItems;
});
}
completedTables++;
progress.Report((completedTables * 100) / totalTables);
}
dispatcherQueue.TryEnqueue(() =>
{
ShowStatus(DataList.Count);
});
}
private async IAsyncEnumerable<object> GetSearchResultsAsync(IQueryable<object> dbSet, string query, [EnumeratorCancellation] CancellationToken cancellationToken)
{
await foreach (var item in dbSet
.Where(x => EF.Property<string>(x, nameof(BasePerson.Mobile)) != null && EF.Property<string>(x, nameof(BasePerson.Mobile)).Contains(query))
.AsAsyncEnumerable()
.WithCancellation(cancellationToken))
{
yield return item;
}
}