Skip to content

Commit

Permalink
[ODS-4944] Session Name case in studentSchoolAttendanceEvnts is not e…
Browse files Browse the repository at this point in the history
…nforced in POST, but breaks GET
  • Loading branch information
gmcelhanon authored and AxelMarquez committed Apr 26, 2022
1 parent ef15092 commit 92d760a
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,65 +16,69 @@
using EdFi.Ods.Common.Infrastructure.Pipelines.Delete;
using EdFi.Ods.Common.Infrastructure.Pipelines.GetDeletedResource;
using EdFi.Ods.Common.Infrastructure.Pipelines.GetMany;
using NHibernate;

namespace EdFi.Ods.Api.Infrastructure.Pipelines.Factories
{
public class PipelineFactory : IPipelineFactory
{
private readonly IServiceLocator _locator;
private readonly IDeletePipelineStepsProvider deletePipelineStepsProvider;
private readonly IGetBySpecificationPipelineStepsProvider getBySpecificationPipelineStepsProvider;
private readonly IGetPipelineStepsProvider getPipelineStepsProvider;
private readonly IGetDeletedResourceIdsPipelineStepsProvider getDeletedResourceIdsPipelineStepsProvider;
private readonly IPutPipelineStepsProvider putPipelineStepsProvider;
private readonly IDeletePipelineStepsProvider _deletePipelineStepsProvider;
private readonly IGetBySpecificationPipelineStepsProvider _getBySpecificationPipelineStepsProvider;
private readonly IGetPipelineStepsProvider _getPipelineStepsProvider;
private readonly IGetDeletedResourceIdsPipelineStepsProvider _getDeletedResourceIdsPipelineStepsProvider;
private readonly IPutPipelineStepsProvider _putPipelineStepsProvider;
private readonly ISessionFactory _sessionFactory;

public PipelineFactory(
IServiceLocator locator,
IGetPipelineStepsProvider getPipelineStepsProvider,
IGetBySpecificationPipelineStepsProvider getBySpecificationPipelineStepsProvider,
IGetDeletedResourceIdsPipelineStepsProvider getDeletedResourceIdsPipelineStepsProvider,
IPutPipelineStepsProvider putPipelineStepsProvider,
IDeletePipelineStepsProvider deletePipelineStepsProvider)
IDeletePipelineStepsProvider deletePipelineStepsProvider,
ISessionFactory sessionFactory)
{
_locator = locator;
this.getPipelineStepsProvider = getPipelineStepsProvider;
this.getBySpecificationPipelineStepsProvider = getBySpecificationPipelineStepsProvider;
this.getDeletedResourceIdsPipelineStepsProvider = getDeletedResourceIdsPipelineStepsProvider;
this.putPipelineStepsProvider = putPipelineStepsProvider;
this.deletePipelineStepsProvider = deletePipelineStepsProvider;
_getPipelineStepsProvider = getPipelineStepsProvider;
_getBySpecificationPipelineStepsProvider = getBySpecificationPipelineStepsProvider;
_getDeletedResourceIdsPipelineStepsProvider = getDeletedResourceIdsPipelineStepsProvider;
_putPipelineStepsProvider = putPipelineStepsProvider;
_deletePipelineStepsProvider = deletePipelineStepsProvider;
_sessionFactory = sessionFactory;
}

public GetPipeline<TResourceModel, TEntityModel> CreateGetPipeline<TResourceModel, TEntityModel>()
where TResourceModel : IHasETag
where TEntityModel : class
{
var stepTypes = getPipelineStepsProvider.GetSteps();
var stepTypes = _getPipelineStepsProvider.GetSteps();

var steps =
ResolvePipelineSteps<GetContext<TEntityModel>, GetResult<TResourceModel>, TResourceModel, TEntityModel>(
stepTypes);

return new GetPipeline<TResourceModel, TEntityModel>(steps);
return new GetPipeline<TResourceModel, TEntityModel>(steps, _sessionFactory);
}

public GetManyPipeline<TResourceModel, TEntityModel> CreateGetManyPipeline<TResourceModel, TEntityModel>()
where TResourceModel : IHasETag
where TEntityModel : class
{
var stepTypes = getBySpecificationPipelineStepsProvider.GetSteps();
var stepTypes = _getBySpecificationPipelineStepsProvider.GetSteps();

var steps =
ResolvePipelineSteps<GetManyContext<TResourceModel, TEntityModel>, GetManyResult<TResourceModel>, TResourceModel,
TEntityModel>(
stepTypes);

return new GetManyPipeline<TResourceModel, TEntityModel>(steps);
return new GetManyPipeline<TResourceModel, TEntityModel>(steps, _sessionFactory);
}

public GetDeletedResourcePipeline<TEntityModel> CreateGetDeletedResourcePipeline<TResourceModel, TEntityModel>()
where TEntityModel : class
{
var stepsTypes = getDeletedResourceIdsPipelineStepsProvider.GetSteps();
var stepsTypes = _getDeletedResourceIdsPipelineStepsProvider.GetSteps();

var steps =
ResolvePipelineSteps<GetDeletedResourceContext<TEntityModel>, GetDeletedResourceResult, TResourceModel,
Expand All @@ -87,7 +91,7 @@ public PutPipeline<TResourceModel, TEntityModel> CreatePutPipeline<TResourceMode
where TEntityModel : class, IHasIdentifier, new()
where TResourceModel : IHasETag
{
var stepTypes = putPipelineStepsProvider.GetSteps();
var stepTypes = _putPipelineStepsProvider.GetSteps();

var steps =
ResolvePipelineSteps<PutContext<TResourceModel, TEntityModel>, PutResult, TResourceModel, TEntityModel>(
Expand All @@ -98,7 +102,7 @@ public PutPipeline<TResourceModel, TEntityModel> CreatePutPipeline<TResourceMode

public DeletePipeline CreateDeletePipeline<TResourceModel, TEntityModel>()
{
var stepTypes = deletePipelineStepsProvider.GetSteps();
var stepTypes = _deletePipelineStepsProvider.GetSteps();
var steps = ResolvePipelineSteps<DeleteContext, DeleteResult, TResourceModel, TEntityModel>(stepTypes);
return new DeletePipeline(steps);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@

using EdFi.Ods.Common;
using EdFi.Ods.Common.Infrastructure.Pipelines;
using NHibernate;

namespace EdFi.Ods.Api.Infrastructure.Pipelines.Get
{
public class GetPipeline<TResourceModel, TEntityModel> : PipelineBase<GetContext<TEntityModel>, GetResult<TResourceModel>>
where TResourceModel : IHasETag
where TEntityModel : class
{
public GetPipeline(IStep<GetContext<TEntityModel>, GetResult<TResourceModel>>[] steps)
: base(steps) { }
public GetPipeline(IStep<GetContext<TEntityModel>, GetResult<TResourceModel>>[] steps, ISessionFactory sessionFactory)
: base(steps, sessionFactory) { }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using EdFi.Ods.Common;
using EdFi.Ods.Common.Infrastructure.Pipelines;
using EdFi.Ods.Common.Infrastructure.Pipelines.GetMany;
using NHibernate;

namespace EdFi.Ods.Api.Infrastructure.Pipelines.GetMany
{
Expand All @@ -14,7 +15,9 @@ public class GetManyPipeline<TResourceModel, TEntityModel>
where TResourceModel : IHasETag
where TEntityModel : class
{
public GetManyPipeline(IStep<GetManyContext<TResourceModel, TEntityModel>, GetManyResult<TResourceModel>>[] steps)
: base(steps) { }
public GetManyPipeline(
IStep<GetManyContext<TResourceModel, TEntityModel>, GetManyResult<TResourceModel>>[] steps,
ISessionFactory sessionFactory)
: base(steps, sessionFactory) { }
}
}
59 changes: 50 additions & 9 deletions Application/EdFi.Ods.Api/Infrastructure/Pipelines/PipelineBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
using System.Threading;
using System.Threading.Tasks;
using EdFi.Common.Extensions;
using EdFi.Ods.Common.Extensions;
using EdFi.Ods.Common.Infrastructure;
using EdFi.Ods.Common.Infrastructure.Pipelines;
using NHibernate;

namespace EdFi.Ods.Api.Infrastructure.Pipelines
{
Expand All @@ -21,11 +22,28 @@ public interface IPipeline
public abstract class PipelineBase<TContext, TResult> : IPipeline
where TResult : PipelineResultBase, new()
{
private readonly IStep<TContext, TResult>[] steps;
private readonly IStep<TContext, TResult>[] _steps;
private readonly ISessionFactory _sessionFactory;

/// <summary>
/// Initializes an instance of the PipelineBase.
/// </summary>
/// <param name="steps">The pipeline steps to be executed.</param>
protected PipelineBase(IStep<TContext, TResult>[] steps)
{
this.steps = steps;
_steps = steps;
}

/// <summary>
/// Initializes an instance of the PipelineBase with a session factory for enabling NHibernate
/// lazy loading features to function under exceptional conditions during GET request processing.
/// </summary>
/// <param name="steps">The pipeline steps to be executed.</param>
/// <param name="sessionFactory">The NHibernate <see cref="ISessionFactory" />.</param>
protected PipelineBase(IStep<TContext, TResult>[] steps, ISessionFactory sessionFactory)
: this(steps)
{
_sessionFactory = sessionFactory;
}

public object Process(object context) => ProcessAsync((TContext) context, CancellationToken.None).GetResultSafely();
Expand All @@ -39,16 +57,39 @@ public async Task<TResult> ProcessAsync(TContext context, CancellationToken canc
{
var result = new TResult();

foreach (var step in steps)
{
await step.ExecuteAsync(context, result, cancellationToken);
// NOTE: The sessionScope will allow NHibernate lazy-loading features to function correctly in exceptional
// conditions during GET request processing. In particular, this can be an issue if during mapping of the
// entity data to resource data, the "ReferenceData" object hasn't been properly hydrated by NHibernate due to
// a casing mismatch between the value for the property on the current entity and the referenced entity's value
// as it exists the database. While SQL Server uses case-insensitive collation by default, NHibernate
// fails to recognize the "reference data" that has already been retrieved for the reference as relevant for
// hydrating the ReferenceData object. This leaves an uninitialized "proxy" object, which when referenced by
// the entity-to-resource mapper, causes NHibernate to perform lazy initialization and go back to the
// database to fetch it. Without the session still available here, an exception will occur.

// Establish a session scope if we have a session factory available here
var sessionScope = _sessionFactory == null
? null
: new SessionScope(_sessionFactory);

// If we have experienced an exception, quit processing steps now
if (result.Exception != null)
try
{
foreach (var step in _steps)
{
break;
await step.ExecuteAsync(context, result, cancellationToken);

// If we have experienced an exception, quit processing steps now
if (result.Exception != null)
{
break;
}
}
}
finally
{
// Close the session, if one exists
sessionScope?.Dispose();
}

return result;
}
Expand Down

0 comments on commit 92d760a

Please sign in to comment.