Browse Source

Remove compiled queries from the EF Core 2.x stores

pull/2236/head
Kévin Chalet 7 years ago
parent
commit
880b0e1eb7
  1. 79
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictApplicationStore.cs
  2. 159
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs
  3. 70
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictScopeStore.cs
  4. 205
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs

79
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictApplicationStore.cs

@ -16,7 +16,6 @@ using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
@ -273,15 +272,6 @@ namespace OpenIddict.EntityFrameworkCore
}
}
/// <summary>
/// Exposes a compiled query allowing to retrieve an application using its client identifier.
/// </summary>
private static readonly Func<TContext, string, Task<TApplication>> FindByClientId =
EF.CompileAsyncQuery((TContext context, string identifier) =>
(from application in context.Set<TApplication>().AsTracking()
where application.ClientId == identifier
select application).FirstOrDefault());
/// <summary>
/// Retrieves an application using its client identifier.
/// </summary>
@ -298,18 +288,11 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
return FindByClientId(Context, identifier);
return (from application in Applications.AsTracking()
where application.ClientId == identifier
select application).FirstOrDefaultAsync(cancellationToken);
}
/// <summary>
/// Exposes a compiled query allowing to retrieve an application using its unique identifier.
/// </summary>
private static readonly Func<TContext, TKey, Task<TApplication>> FindById =
EF.CompileAsyncQuery((TContext context, TKey identifier) =>
(from application in context.Set<TApplication>().AsTracking()
where application.Id.Equals(identifier)
select application).FirstOrDefault());
/// <summary>
/// Retrieves an application using its unique identifier.
/// </summary>
@ -326,23 +309,12 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
return FindById(Context, ConvertIdentifierFromString(identifier));
}
var key = ConvertIdentifierFromString(identifier);
/// <summary>
/// Exposes a compiled query allowing to retrieve all the applications
/// associated with the specified post_logout_redirect_uri.
/// </summary>
private static readonly Func<TContext, string, AsyncEnumerable<TApplication>> FindByPostLogoutRedirectUri =
// To optimize the efficiency of the query a bit, only applications whose stringified
// PostLogoutRedirectUris contains the specified URL are returned. Once the applications
// are retrieved, a second pass is made to ensure only valid elements are returned.
// Implementers that use this query in a hot path may want to override this method
// to use SQL Server 2016 functions like JSON_VALUE to make the query more efficient.
EF.CompileAsyncQuery((TContext context, string address) =>
from application in context.Set<TApplication>().AsTracking()
where application.PostLogoutRedirectUris.Contains(address)
select application);
return (from application in Applications.AsTracking()
where application.Id.Equals(key)
select application).FirstOrDefaultAsync(cancellationToken);
}
/// <summary>
/// Retrieves all the applications associated with the specified post_logout_redirect_uri.
@ -361,7 +333,15 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The address cannot be null or empty.", nameof(address));
}
var applications = await FindByPostLogoutRedirectUri(Context, address).ToListAsync(cancellationToken);
// To optimize the efficiency of the query a bit, only applications whose stringified
// PostLogoutRedirectUris contains the specified URL are returned. Once the applications
// are retrieved, a second pass is made to ensure only valid elements are returned.
// Implementers that use this method in a hot path may want to override this method
// to use SQL Server 2016 functions like JSON_VALUE to make the query more efficient.
var applications = await (from application in Applications.AsTracking()
where application.PostLogoutRedirectUris.Contains(address)
select application).ToListAsync(cancellationToken);
var builder = ImmutableArray.CreateBuilder<TApplication>(applications.Count);
foreach (var application in applications)
@ -384,21 +364,6 @@ namespace OpenIddict.EntityFrameworkCore
builder.ToImmutable();
}
/// <summary>
/// Exposes a compiled query allowing to retrieve all the
/// applications associated with the specified redirect_uri.
/// </summary>
private static readonly Func<TContext, string, AsyncEnumerable<TApplication>> FindByRedirectUri =
// To optimize the efficiency of the query a bit, only applications whose stringified
// RedirectUris property contains the specified URL are returned. Once the applications
// are retrieved, a second pass is made to ensure only valid elements are returned.
// Implementers that use this query in a hot path may want to override this method
// to use SQL Server 2016 functions like JSON_VALUE to make the query more efficient.
EF.CompileAsyncQuery((TContext context, string address) =>
from application in context.Set<TApplication>().AsTracking()
where application.RedirectUris.Contains(address)
select application);
/// <summary>
/// Retrieves all the applications associated with the specified redirect_uri.
/// </summary>
@ -416,7 +381,15 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The address cannot be null or empty.", nameof(address));
}
var applications = await FindByRedirectUri(Context, address).ToListAsync(cancellationToken);
// To optimize the efficiency of the query a bit, only applications whose stringified
// RedirectUris property contains the specified URL are returned. Once the applications
// are retrieved, a second pass is made to ensure only valid elements are returned.
// Implementers that use this method in a hot path may want to override this method
// to use SQL Server 2016 functions like JSON_VALUE to make the query more efficient.
var applications = await (from application in Applications.AsTracking()
where application.RedirectUris.Contains(address)
select application).ToListAsync(cancellationToken);
var builder = ImmutableArray.CreateBuilder<TApplication>(applications.Count);
foreach (var application in applications)

159
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs

@ -16,7 +16,6 @@ using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
@ -249,24 +248,6 @@ namespace OpenIddict.EntityFrameworkCore
}
}
/// <summary>
/// Exposes a compiled query allowing to retrieve the authorizations corresponding
/// to the specified subject and associated with the application identifier.
/// </summary>
private static readonly Func<TContext, TKey, string, AsyncEnumerable<TAuthorization>> FindBySubjectAndClient =
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be
// filtered using authorization.Application.Id.Equals(key). To work around this issue,
// this compiled query uses an explicit join before applying the equality check.
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
EF.CompileAsyncQuery((TContext context, TKey identifier, string subject) =>
from authorization in context.Set<TAuthorization>()
.Include(authorization => authorization.Application)
.AsTracking()
where authorization.Subject == subject
join application in context.Set<TApplication>().AsTracking() on authorization.Application.Id equals application.Id
where application.Id.Equals(identifier)
select authorization);
/// <summary>
/// Retrieves the authorizations corresponding to the specified
/// subject and associated with the application identifier.
@ -291,26 +272,20 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The client cannot be null or empty.", nameof(client));
}
return ImmutableArray.CreateRange(await FindBySubjectAndClient(Context,
ConvertIdentifierFromString(client), subject).ToListAsync(cancellationToken));
}
/// <summary>
/// Exposes a compiled query allowing to retrieve the authorizations matching the specified parameters.
/// </summary>
private static readonly Func<TContext, TKey, string, string, AsyncEnumerable<TAuthorization>> FindBySubjectClientAndStatus =
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be
// filtered using authorization.Application.Id.Equals(key). To work around this issue,
// this compiled query uses an explicit join before applying the equality check.
// this method is overriden to use an explicit join before applying the equality check.
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
EF.CompileAsyncQuery((TContext context, TKey identifier, string subject, string status) =>
from authorization in context.Set<TAuthorization>()
.Include(authorization => authorization.Application)
.AsTracking()
where authorization.Subject == subject && authorization.Status == status
join application in context.Set<TApplication>().AsTracking() on authorization.Application.Id equals application.Id
where application.Id.Equals(identifier)
select authorization);
var key = ConvertIdentifierFromString(client);
return ImmutableArray.CreateRange(
await (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking()
where authorization.Subject == subject
join application in Applications.AsTracking() on authorization.Application.Id equals application.Id
where application.Id.Equals(key)
select authorization).ToListAsync(cancellationToken));
}
/// <summary>
/// Retrieves the authorizations matching the specified parameters.
@ -342,28 +317,20 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The status cannot be null or empty.", nameof(status));
}
return ImmutableArray.CreateRange(await FindBySubjectClientAndStatus(Context,
ConvertIdentifierFromString(client), subject, status).ToListAsync(cancellationToken));
}
/// <summary>
/// Exposes a compiled query allowing to retrieve the authorizations matching the specified parameters.
/// </summary>
private static readonly Func<TContext, TKey, string, string, string, AsyncEnumerable<TAuthorization>> FindBySubjectClientStatusAndType =
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be
// filtered using authorization.Application.Id.Equals(key). To work around this issue,
// this compiled query uses an explicit join before applying the equality check.
// this method is overriden to use an explicit join before applying the equality check.
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
EF.CompileAsyncQuery((TContext context, TKey identifier, string subject, string status, string type) =>
from authorization in context.Set<TAuthorization>()
.Include(authorization => authorization.Application)
.AsTracking()
where authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type
join application in context.Set<TApplication>().AsTracking() on authorization.Application.Id equals application.Id
where application.Id.Equals(identifier)
select authorization);
var key = ConvertIdentifierFromString(client);
return ImmutableArray.CreateRange(
await (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking()
where authorization.Subject == subject && authorization.Status == status
join application in Applications.AsTracking() on authorization.Application.Id equals application.Id
where application.Id.Equals(key)
select authorization).ToListAsync(cancellationToken));
}
/// <summary>
/// Retrieves the authorizations matching the specified parameters.
@ -401,8 +368,21 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The type cannot be null or empty.", nameof(type));
}
return ImmutableArray.CreateRange(await FindBySubjectClientStatusAndType(Context,
ConvertIdentifierFromString(client), subject, status, type).ToListAsync(cancellationToken));
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be
// filtered using authorization.Application.Id.Equals(key). To work around this issue,
// this method is overriden to use an explicit join before applying the equality check.
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
var key = ConvertIdentifierFromString(client);
return ImmutableArray.CreateRange(
await (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking()
where authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type
join application in Applications.AsTracking() on authorization.Application.Id equals application.Id
where application.Id.Equals(key)
select authorization).ToListAsync(cancellationToken));
}
/// <summary>
@ -449,23 +429,6 @@ namespace OpenIddict.EntityFrameworkCore
builder.ToImmutable();
}
/// <summary>
/// Exposes a compiled query allowing to retrieve the list of
/// authorizations corresponding to the specified application identifier.
/// </summary>
private static readonly Func<TContext, TKey, AsyncEnumerable<TAuthorization>> FindByApplicationId =
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be
// filtered using authorization.Application.Id.Equals(key). To work around this issue,
// this compiled query uses an explicit join before applying the equality check.
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
EF.CompileAsyncQuery((TContext context, TKey identifier) =>
from authorization in context.Set<TAuthorization>()
.Include(authorization => authorization.Application)
.AsTracking()
join application in context.Set<TApplication>().AsTracking() on authorization.Application.Id equals application.Id
where application.Id.Equals(identifier)
select authorization);
/// <summary>
/// Retrieves the list of authorizations corresponding to the specified application identifier.
/// </summary>
@ -483,20 +446,19 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
return ImmutableArray.CreateRange(await FindByApplicationId(Context,
ConvertIdentifierFromString(identifier)).ToListAsync(cancellationToken));
}
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be
// filtered using authorization.Application.Id.Equals(key). To work around this issue,
// this method is overriden to use an explicit join before applying the equality check.
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
/// <summary>
/// Exposes a compiled query allowing to retrieve an authorization using its unique identifier.
/// </summary>
private static readonly Func<TContext, TKey, Task<TAuthorization>> FindById =
EF.CompileAsyncQuery((TContext context, TKey identifier) =>
(from authorization in context.Set<TAuthorization>()
.Include(authorization => authorization.Application)
.AsTracking()
where authorization.Id.Equals(identifier)
select authorization).FirstOrDefault());
var key = ConvertIdentifierFromString(identifier);
return ImmutableArray.CreateRange(
await (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking()
join application in Applications.AsTracking() on authorization.Application.Id equals application.Id
where application.Id.Equals(identifier)
select authorization).ToListAsync(cancellationToken));
}
/// <summary>
/// Retrieves an authorization using its unique identifier.
@ -514,20 +476,12 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
return FindById(Context, ConvertIdentifierFromString(identifier));
}
var key = ConvertIdentifierFromString(identifier);
/// <summary>
/// Exposes a compiled query allowing to retrieve all the
/// authorizations corresponding to the specified subject.
/// </summary>
private static readonly Func<TContext, string, AsyncEnumerable<TAuthorization>> FindBySubject =
EF.CompileAsyncQuery((TContext context, string subject) =>
from authorization in context.Set<TAuthorization>()
.Include(authorization => authorization.Application)
.AsTracking()
where authorization.Subject == subject
select authorization);
return (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking()
where authorization.Id.Equals(key)
select authorization).FirstOrDefaultAsync(cancellationToken);
}
/// <summary>
/// Retrieves .
@ -546,7 +500,10 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject));
}
return ImmutableArray.CreateRange(await FindBySubject(Context, subject).ToListAsync(cancellationToken));
return ImmutableArray.CreateRange(
await (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking()
where authorization.Subject == subject
select authorization).ToListAsync(cancellationToken));
}
/// <summary>

70
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictScopeStore.cs

@ -13,7 +13,6 @@ using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
@ -180,15 +179,6 @@ namespace OpenIddict.EntityFrameworkCore
}
}
/// <summary>
/// Exposes a compiled query allowing to retrieve a scope using its unique identifier.
/// </summary>
private static readonly Func<TContext, TKey, Task<TScope>> FindById =
EF.CompileAsyncQuery((TContext context, TKey identifier) =>
(from scope in context.Set<TScope>().AsTracking()
where scope.Id.Equals(identifier)
select scope).FirstOrDefault());
/// <summary>
/// Retrieves a scope using its unique identifier.
/// </summary>
@ -205,17 +195,12 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
return FindById(Context, ConvertIdentifierFromString(identifier));
}
var key = ConvertIdentifierFromString(identifier);
/// <summary>
/// Exposes a compiled query allowing to retrieve a scope using its name.
/// </summary>
private static readonly Func<TContext, string, Task<TScope>> FindByName =
EF.CompileAsyncQuery((TContext context, string name) =>
(from scope in context.Set<TScope>().AsTracking()
where scope.Name == name
select scope).FirstOrDefault());
return (from scope in Scopes.AsTracking()
where scope.Id.Equals(key)
select scope).FirstOrDefaultAsync(cancellationToken);
}
/// <summary>
/// Retrieves a scope using its name.
@ -233,18 +218,11 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The scope name cannot be null or empty.", nameof(name));
}
return FindByName(Context, name);
return (from scope in Scopes.AsTracking()
where scope.Name == name
select scope).FirstOrDefaultAsync(cancellationToken);
}
/// <summary>
/// Exposes a compiled query allowing to retrieve a list of scopes using their name.
/// </summary>
private static readonly Func<TContext, ImmutableArray<string>, AsyncEnumerable<TScope>> FindByNames =
EF.CompileAsyncQuery((TContext context, ImmutableArray<string> names) =>
from scope in context.Set<TScope>().AsTracking()
where names.Contains(scope.Name)
select scope);
/// <summary>
/// Retrieves a list of scopes using their name.
/// </summary>
@ -262,23 +240,12 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("Scope names cannot be null or empty.", nameof(names));
}
return ImmutableArray.CreateRange(await FindByNames(Context, names).ToListAsync(cancellationToken));
return ImmutableArray.CreateRange(
await (from scope in Scopes.AsTracking()
where names.Contains(scope.Name)
select scope).ToListAsync(cancellationToken));
}
/// <summary>
/// Exposes a compiled query allowing to retrieve all the scopes that contain the specified resource.
/// </summary>
private static readonly Func<TContext, string, AsyncEnumerable<TScope>> FindByResource =
// To optimize the efficiency of the query a bit, only scopes whose stringified
// Resources column contains the specified resource are returned. Once the scopes
// are retrieved, a second pass is made to ensure only valid elements are returned.
// Implementers that use this query in a hot path may want to override this method
// to use SQL Server 2016 functions like JSON_VALUE to make the query more efficient.
EF.CompileAsyncQuery((TContext context, string resource) =>
from scope in context.Set<TScope>().AsTracking()
where scope.Resources.Contains(resource)
select scope);
/// <summary>
/// Retrieves all the scopes that contain the specified resource.
/// </summary>
@ -296,12 +263,21 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The resource cannot be null or empty.", nameof(resource));
}
// To optimize the efficiency of the query a bit, only scopes whose stringified
// Resources column contains the specified resource are returned. Once the scopes
// are retrieved, a second pass is made to ensure only valid elements are returned.
// Implementers that use this method in a hot path may want to override this method
// to use SQL Server 2016 functions like JSON_VALUE to make the query more efficient.
var scopes = await (from scope in Scopes.AsTracking()
where scope.Resources.Contains(resource)
select scope).ToListAsync(cancellationToken);
var builder = ImmutableArray.CreateBuilder<TScope>();
foreach (var scope in await FindByResource(Context, resource).ToListAsync(cancellationToken))
foreach (var scope in scopes)
{
var resources = await GetResourcesAsync(scope, cancellationToken);
if (resources.Contains(resource, StringComparer.Ordinal))
if (resources.Contains(resource, StringComparer.OrdinalIgnoreCase))
{
builder.Add(scope);
}

205
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs

@ -16,7 +16,6 @@ using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
@ -202,25 +201,6 @@ namespace OpenIddict.EntityFrameworkCore
}
}
/// <summary>
/// Exposes a compiled query allowing to retrieve the tokens corresponding
/// to the specified subject and associated with the application identifier.
/// </summary>
private static readonly Func<TContext, TKey, string, AsyncEnumerable<TToken>> FindBySubjectAndClient =
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be
// filtered using token.Application.Id.Equals(key). To work around this issue,
// this compiled query uses an explicit join before applying the equality check.
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
EF.CompileAsyncQuery((TContext context, TKey identifier, string subject) =>
from token in context.Set<TToken>()
.Include(token => token.Application)
.Include(token => token.Authorization)
.AsTracking()
where token.Subject == subject
join application in context.Set<TApplication>().AsTracking() on token.Application.Id equals application.Id
where application.Id.Equals(identifier)
select token);
/// <summary>
/// Retrieves the tokens corresponding to the specified
/// subject and associated with the application identifier.
@ -245,27 +225,20 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The client cannot be null or empty.", nameof(client));
}
return ImmutableArray.CreateRange(await FindBySubjectAndClient(Context,
ConvertIdentifierFromString(client), subject).ToListAsync(cancellationToken));
}
/// <summary>
/// Exposes a compiled query allowing to retrieve the tokens matching the specified parameters.
/// </summary>
private static readonly Func<TContext, TKey, string, string, AsyncEnumerable<TToken>> FindBySubjectClientAndStatus =
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be
// filtered using token.Application.Id.Equals(key). To work around this issue,
// this compiled query uses an explicit join before applying the equality check.
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
EF.CompileAsyncQuery((TContext context, TKey identifier, string subject, string status) =>
from token in context.Set<TToken>()
.Include(token => token.Application)
.Include(token => token.Authorization)
.AsTracking()
where token.Subject == subject && token.Status == status
join application in context.Set<TApplication>().AsTracking() on token.Application.Id equals application.Id
where application.Id.Equals(identifier)
select token);
var key = ConvertIdentifierFromString(client);
return ImmutableArray.CreateRange(
await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking()
where token.Subject == subject
join application in Applications.AsTracking() on token.Application.Id equals application.Id
where application.Id.Equals(key)
select token).ToListAsync(cancellationToken));
}
/// <summary>
/// Retrieves the tokens matching the specified parameters.
@ -297,29 +270,21 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The status cannot be null or empty.", nameof(status));
}
return ImmutableArray.CreateRange(await FindBySubjectClientAndStatus(Context,
ConvertIdentifierFromString(client), subject, status).ToListAsync(cancellationToken));
}
/// <summary>
/// Exposes a compiled query allowing to retrieve the tokens matching the specified parameters.
/// </summary>
private static readonly Func<TContext, TKey, string, string, string, AsyncEnumerable<TToken>> FindBySubjectClientStatusAndType =
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be
// filtered using token.Application.Id.Equals(key). To work around this issue,
// this compiled query uses an explicit join before applying the equality check.
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
EF.CompileAsyncQuery((TContext context, TKey identifier, string subject, string status, string type) =>
from token in context.Set<TToken>()
.Include(token => token.Application)
.Include(token => token.Authorization)
.AsTracking()
where token.Subject == subject &&
token.Status == status &&
token.Type == type
join application in context.Set<TApplication>().AsTracking() on token.Application.Id equals application.Id
where application.Id.Equals(identifier)
select token);
var key = ConvertIdentifierFromString(client);
return ImmutableArray.CreateRange(
await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking()
where token.Subject == subject &&
token.Status == status
join application in Applications.AsTracking() on token.Application.Id equals application.Id
where application.Id.Equals(key)
select token).ToListAsync(cancellationToken));
}
/// <summary>
/// Retrieves the tokens matching the specified parameters.
@ -357,27 +322,22 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The type cannot be null or empty.", nameof(type));
}
return ImmutableArray.CreateRange(await FindBySubjectClientStatusAndType(Context,
ConvertIdentifierFromString(client), subject, status, type).ToListAsync(cancellationToken));
}
/// <summary>
/// Exposes a compiled query allowing to retrieve the list of
/// tokens corresponding to the specified application identifier.
/// </summary>
private static readonly Func<TContext, TKey, AsyncEnumerable<TToken>> FindByApplicationId =
// Note: due to a bug in Entity Framework Core's query visitor, the tokens can't be
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be
// filtered using token.Application.Id.Equals(key). To work around this issue,
// this compiled query uses an explicit join before applying the equality check.
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
EF.CompileAsyncQuery((TContext context, TKey identifier) =>
from token in context.Set<TToken>()
.Include(token => token.Application)
.Include(token => token.Authorization)
.AsTracking()
join application in context.Set<TApplication>().AsTracking() on token.Application.Id equals application.Id
where application.Id.Equals(identifier)
select token);
var key = ConvertIdentifierFromString(client);
return ImmutableArray.CreateRange(
await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking()
where token.Subject == subject &&
token.Status == status &&
token.Type == type
join application in Applications.AsTracking() on token.Application.Id equals application.Id
where application.Id.Equals(key)
select token).ToListAsync(cancellationToken));
}
/// <summary>
/// Retrieves the list of tokens corresponding to the specified application identifier.
@ -395,27 +355,19 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
return ImmutableArray.CreateRange(await FindByApplicationId(Context,
ConvertIdentifierFromString(identifier)).ToListAsync(cancellationToken));
}
/// <summary>
/// Exposes a compiled query allowing to retrieve the list of
/// tokens corresponding to the specified authorization identifier.
/// </summary>
private static readonly Func<TContext, TKey, AsyncEnumerable<TToken>> FindByAuthorizationId =
// Note: due to a bug in Entity Framework Core's query visitor, the tokens can't be
// filtered using token.Authorization.Id.Equals(key). To work around this issue,
// this compiled query uses an explicit join before applying the equality check.
// filtered using token.Application.Id.Equals(key). To work around this issue,
// this method is overriden to use an explicit join before applying the equality check.
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
EF.CompileAsyncQuery((TContext context, TKey identifier) =>
from token in context.Set<TToken>()
.Include(token => token.Application)
.Include(token => token.Authorization)
.AsTracking()
join authorization in context.Set<TAuthorization>().AsTracking() on token.Authorization.Id equals authorization.Id
where authorization.Id.Equals(identifier)
select token);
var key = ConvertIdentifierFromString(identifier);
return ImmutableArray.CreateRange(
await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking()
join application in Applications.AsTracking() on token.Application.Id equals application.Id
where application.Id.Equals(key)
select token).ToListAsync(cancellationToken));
}
/// <summary>
/// Retrieves the list of tokens corresponding to the specified authorization identifier.
@ -433,21 +385,19 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
return ImmutableArray.CreateRange(await FindByAuthorizationId(Context,
ConvertIdentifierFromString(identifier)).ToListAsync(cancellationToken));
}
// Note: due to a bug in Entity Framework Core's query visitor, the tokens can't be
// filtered using token.Authorization.Id.Equals(key). To work around this issue,
// this method is overriden to use an explicit join before applying the equality check.
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
/// <summary>
/// Exposes a compiled query allowing to retrieve a token using its unique identifier.
/// </summary>
private static readonly Func<TContext, TKey, Task<TToken>> FindById =
EF.CompileAsyncQuery((TContext context, TKey identifier) =>
(from token in context.Set<TToken>()
.Include(token => token.Application)
.Include(token => token.Authorization)
.AsTracking()
where token.Id.Equals(identifier)
select token).FirstOrDefault());
var key = ConvertIdentifierFromString(identifier);
return ImmutableArray.CreateRange(
await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking()
join authorization in Authorizations.AsTracking() on token.Authorization.Id equals authorization.Id
where authorization.Id.Equals(key)
select token).ToListAsync(cancellationToken));
}
/// <summary>
/// Retrieves a token using its unique identifier.
@ -465,21 +415,12 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
return FindById(Context, ConvertIdentifierFromString(identifier));
}
var key = ConvertIdentifierFromString(identifier);
/// <summary>
/// Exposes a compiled query allowing to retrieve the list of
/// tokens corresponding to the specified reference identifier.
/// </summary>
private static readonly Func<TContext, string, Task<TToken>> FindByReferenceId =
EF.CompileAsyncQuery((TContext context, string identifier) =>
(from token in context.Set<TToken>()
.Include(token => token.Application)
.Include(token => token.Authorization)
.AsTracking()
where token.ReferenceId == identifier
select token).FirstOrDefault());
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking()
where token.Id.Equals(key)
select token).FirstOrDefaultAsync(cancellationToken);
}
/// <summary>
/// Retrieves the list of tokens corresponding to the specified reference identifier.
@ -498,22 +439,11 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier));
}
return FindByReferenceId(Context, identifier);
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking()
where token.ReferenceId == identifier
select token).FirstOrDefaultAsync(cancellationToken);
}
/// <summary>
/// Exposes a compiled query allowing to retrieve the
/// list of tokens corresponding to the specified subject.
/// </summary>
private static readonly Func<TContext, string, AsyncEnumerable<TToken>> FindBySubject =
EF.CompileAsyncQuery((TContext context, string subject) =>
from token in context.Set<TToken>()
.Include(token => token.Application)
.Include(token => token.Authorization)
.AsTracking()
where token.Subject == subject
select token);
/// <summary>
/// Retrieves the list of tokens corresponding to the specified subject.
/// </summary>
@ -530,7 +460,10 @@ namespace OpenIddict.EntityFrameworkCore
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject));
}
return ImmutableArray.CreateRange(await FindBySubject(Context, subject).ToListAsync(cancellationToken));
return ImmutableArray.CreateRange(
await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking()
where token.Subject == subject
select token).ToListAsync(cancellationToken));
}
/// <summary>

Loading…
Cancel
Save