Skip to content

[DataGrid] Allow EntityFrameworkAsyncQueryExecutor configuration #3272

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
// ------------------------------------------------------------------------
// MIT License - Copyright (c) Microsoft Corporation. All rights reserved.
// ------------------------------------------------------------------------

using Microsoft.FluentUI.AspNetCore.Components.DataGrid.EntityFrameworkAdapter;
using Microsoft.FluentUI.AspNetCore.Components.DataGrid.Infrastructure;

#pragma warning disable IDE0130 // Namespace does not match folder structure
namespace Microsoft.Extensions.DependencyInjection;
#pragma warning restore IDE0130 // Namespace does not match folder structure

/// <summary>
/// Provides extension methods to configure <see cref="IAsyncQueryExecutor"/> on a <see cref="IServiceCollection"/>.
Expand All @@ -12,8 +18,9 @@ public static class EntityFrameworkAdapterServiceCollectionExtensions
/// Registers an Entity Framework aware implementation of <see cref="IAsyncQueryExecutor"/>.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
public static void AddDataGridEntityFrameworkAdapter(this IServiceCollection services)
/// <param name="ignoreException">A function to determine whether to ignore exceptions.</param>
public static void AddDataGridEntityFrameworkAdapter(this IServiceCollection services, Func<Exception, bool>? ignoreException = null)
{
services.AddScoped<IAsyncQueryExecutor, EntityFrameworkAsyncQueryExecutor>();
services.AddScoped<IAsyncQueryExecutor, EntityFrameworkAsyncQueryExecutor>(sp => new EntityFrameworkAsyncQueryExecutor(ignoreException));
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
// ------------------------------------------------------------------------
// MIT License - Copyright (c) Microsoft Corporation. All rights reserved.
// ------------------------------------------------------------------------

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.FluentUI.AspNetCore.Components.DataGrid.Infrastructure;

namespace Microsoft.FluentUI.AspNetCore.Components.DataGrid.EntityFrameworkAdapter;

internal class EntityFrameworkAsyncQueryExecutor : IAsyncQueryExecutor, IDisposable
/// <summary>
/// An <see cref="IAsyncQueryExecutor"/> implementation for Entity Framework Core.
/// </summary>
internal class EntityFrameworkAsyncQueryExecutor(Func<Exception, bool>? ignoreException = null) : IAsyncQueryExecutor, IDisposable
{
private readonly SemaphoreSlim _lock = new(1);

/// <inheritdoc />
public bool IsSupported<T>(IQueryable<T> queryable)
=> queryable.Provider is IAsyncQueryProvider;

/// <inheritdoc />
public Task<int> CountAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken)
=> ExecuteAsync(() => queryable.CountAsync(cancellationToken));

/// <inheritdoc />
public Task<T[]> ToArrayAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken)
=> ExecuteAsync(() => queryable.ToArrayAsync(cancellationToken));

Expand All @@ -36,6 +46,10 @@ private async Task<TResult> ExecuteAsync<TResult>(Func<Task<TResult>> operation)
{
return default!;
}
catch (Exception ex) when (ignoreException?.Invoke(ex) == true)
{
return default!;
}
}

void IDisposable.Dispose() => _lock.Dispose();
Expand Down
18 changes: 16 additions & 2 deletions src/Extensions/DataGrid.EntityFrameworkAdapter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,27 @@ Install the package by running the command:
```
dotnet add package Microsoft.FluentUI.AspNetCore.Components.DataGrid.EntityFrameworkAdapter
```

## Usage
In your Program.cs file you need to add the following:
When using the provided implementation, you need to add add the following in the `Program.cs` file:

```
builder.Services.AddDataGridEntityFrameworkAdapter();
```

## Changing the adapter's behavior
Starting with v4.11.4, the `EntityFrameworkAsyncQueryExecutor` exposes a way to ignore exceptions which may occur during query execution.
This can be useful when you want to handle exceptions in a custom way, for example, by logging them. To ignore exceptions, you can
supply a `Func<Exception, bool>` to the `IgnoreException` property of the `EntityFrameworkAsyncQueryExecutor` instance. The function
should return `true` if the exception should be ignored and `false` otherwise. An example:
```csharp
builder.Services.AddFluentUIComponents()
.AddDataGridEntityFrameworkAdapter(ex => ex is SqlException sqlEx
&& sqlEx.Errors.OfType<SqlError>().Any(e => (e.Class == 11 && e.Number == 0) || (e.Class == 16 && e.Number == 3204)));
```

For more information see also https://github.com/microsoft/fluentui-blazor/issues/3269.


## Support
The Microsoft Fluent UI Blazor library is an open source project and is **not** an official part of ASP.NET Core, which means it’s **not** officially
supported and isn’t committed to ship updates as part of any official .NET updates. It is built and maintained by Microsoft employees (**and** other contributors)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
using Microsoft.FluentUI.AspNetCore.Components.DataGrid.ODataAdapter;
// ------------------------------------------------------------------------
// MIT License - Copyright (c) Microsoft Corporation. All rights reserved.
// ------------------------------------------------------------------------

using Microsoft.FluentUI.AspNetCore.Components.DataGrid.Infrastructure;
using Microsoft.FluentUI.AspNetCore.Components.DataGrid.ODataAdapter;

#pragma warning disable IDE0130 // Namespace does not match folder structure
namespace Microsoft.Extensions.DependencyInjection;
#pragma warning restore IDE0130 // Namespace does not match folder structure

/// <summary>
/// Provides extension methods to configure <see cref="IAsyncQueryExecutor"/> on a <see cref="IServiceCollection"/>.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
using Microsoft.OData.Client;
// ------------------------------------------------------------------------
// MIT License - Copyright (c) Microsoft Corporation. All rights reserved.
// ------------------------------------------------------------------------

using Microsoft.FluentUI.AspNetCore.Components.DataGrid.Infrastructure;
using Microsoft.OData.Client;

namespace Microsoft.FluentUI.AspNetCore.Components.DataGrid.ODataAdapter;

/// <summary>
/// An <see cref="IAsyncQueryExecutor"/> implementation for Microsoft.OData.Client.
/// </summary>
internal class ODataAsyncQueryExecutor : IAsyncQueryExecutor
{
/// <inheritdoc />
public bool IsSupported<T>(IQueryable<T> queryable) => queryable.Provider is DataServiceQueryProvider;

/// <inheritdoc />
public async Task<int> CountAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken)
=> (int)(await ExecuteAsync(((DataServiceQuery<T>)queryable.Take(0)).IncludeCount(), cancellationToken)).Count;

/// <inheritdoc />
public async Task<T[]> ToArrayAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken)
=> [.. await ExecuteAsync(queryable, cancellationToken)];

Expand Down
Loading