Skip to content

Commit

Permalink
[ODS-5868] Add EF Core DbContexts and supporting code to EdFi.Securit…
Browse files Browse the repository at this point in the history
…y.DataAccess (#831)

* Add EF Core DbContext

* Switch to EF Core

* Update tests

* Cleanup

* Fix postgres database names

* Update more tests

* Cleanup

* More test updates

* Revert model change and update package version

* Model update

* Package version

* Update model to reflect nullable column

* Package version

* Remove extra project reference
  • Loading branch information
mjaksn authored Sep 26, 2023
1 parent 0ec39a9 commit bdbc272
Show file tree
Hide file tree
Showing 15 changed files with 74 additions and 202 deletions.
2 changes: 1 addition & 1 deletion Application/EdFi.Ods.Api/EdFi.Ods.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<Otherwise>
<ItemGroup>
<PackageReference Include="EdFi.Suite3.Admin.DataAccess" Version="7.1.6" />
<PackageReference Include="EdFi.Suite3.Security.DataAccess" Version="7.1.4" />
<PackageReference Include="EdFi.Suite3.Security.DataAccess" Version="7.1.10" />
<PackageReference Include="EdFi.Suite3.Common" Version="7.1.2" />
</ItemGroup>
</Otherwise>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
// See the LICENSE and NOTICES files in the project root for more information.

using System;
using System.Data.Entity;
using System.Threading;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
using EdFi.Security.DataAccess.Models;
using Action = EdFi.Security.DataAccess.Models.Action;
Expand Down Expand Up @@ -32,6 +33,6 @@ public interface ISecurityContext : IDisposable

int SaveChanges();

Task<int> SaveChangesAsync();
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,58 +3,22 @@
// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
// See the LICENSE and NOTICES files in the project root for more information.

using System.Data.Entity;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.ModelConfiguration.Conventions;
using EdFi.Common;
using EdFi.Common.Utils.Extensions;
using Microsoft.EntityFrameworkCore;

namespace EdFi.Security.DataAccess.Contexts
{
public class PostgresSecurityContext : SecurityContext
{
public PostgresSecurityContext(string connectionString)
: base(connectionString) { }
public PostgresSecurityContext(DbContextOptions options)
: base(options) { }

protected override void OnModelCreating(DbModelBuilder modelBuilder)
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

modelBuilder.Conventions.Add<ForeignKeyLowerCaseNamingConvention>();
modelBuilder.Conventions.Add<TableLowerCaseNamingConvention>();

modelBuilder.Properties().Configure(c => c.HasColumnName(c.ClrPropertyInfo.Name.ToLowerInvariant()));
}

private class TableLowerCaseNamingConvention : IStoreModelConvention<EntitySet>
{
public void Apply(EntitySet entitySet, DbModel model)
{
Preconditions.ThrowIfNull(entitySet, nameof(entitySet));
Preconditions.ThrowIfNull(model, nameof(model));

entitySet.Table = entitySet.Table.ToLowerInvariant();
}
}

private class ForeignKeyLowerCaseNamingConvention : IStoreModelConvention<AssociationType>
{
public void Apply(AssociationType association, DbModel model)
{
Preconditions.ThrowIfNull(association, nameof(association));
Preconditions.ThrowIfNull(model, nameof(model));

if (!association.IsForeignKey)
{
return;
}

association.Constraint.FromProperties.ForEach(PropertyNamesToLowerInvariant);
association.Constraint.ToProperties.ForEach(PropertyNamesToLowerInvariant);

void PropertyNamesToLowerInvariant(EdmProperty property) => property.Name = property.Name.ToLowerInvariant();
}
modelBuilder.Model.GetEntityTypes().ForEach(entityType =>
entityType.SetSchema("dbo"));
}
}
}
19 changes: 3 additions & 16 deletions Application/EdFi.Security.DataAccess/Contexts/SecurityContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,15 @@
// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
// See the LICENSE and NOTICES files in the project root for more information.

using System.Data.Entity;
using Microsoft.EntityFrameworkCore;
using EdFi.Security.DataAccess.Models;
using EdFi.Security.DataAccess.Utils;

namespace EdFi.Security.DataAccess.Contexts
{
public abstract class SecurityContext : DbContext, ISecurityContext
{
protected SecurityContext(string connectionString)
: base(connectionString)
{
Database.SetInitializer(new ValidateDatabase<SqlServerSecurityContext>());
Database.SetInitializer(new ValidateDatabase<PostgresSecurityContext>());
}
protected SecurityContext(DbContextOptions options)
: base(options) { }

public DbSet<Action> Actions { get; set; }

Expand All @@ -33,13 +28,5 @@ protected SecurityContext(string connectionString)
public DbSet<ClaimSetResourceClaimActionAuthorizationStrategyOverrides> ClaimSetResourceClaimActionAuthorizationStrategyOverrides { get; set; }

public DbSet<ResourceClaimActionAuthorizationStrategies> ResourceClaimActionAuthorizationStrategies { get; set; }

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ResourceClaim>()
.HasOptional(rc => rc.ParentResourceClaim)
.WithMany()
.HasForeignKey(fk => fk.ParentResourceClaimId);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Collections.Generic;
using EdFi.Common.Configuration;
using EdFi.Security.DataAccess.Providers;
using Microsoft.EntityFrameworkCore;

namespace EdFi.Security.DataAccess.Contexts
{
Expand All @@ -17,21 +18,49 @@ public class SecurityContextFactory : ISecurityContextFactory
private readonly IDictionary<DatabaseEngine, Type> _securityContextTypeByDatabaseEngine =
new Dictionary<DatabaseEngine, Type>
{
{DatabaseEngine.SqlServer, typeof(SqlServerSecurityContext)},
{DatabaseEngine.Postgres, typeof(PostgresSecurityContext)}
{ DatabaseEngine.SqlServer, typeof(SqlServerSecurityContext) },
{ DatabaseEngine.Postgres, typeof(PostgresSecurityContext) }
};

public SecurityContextFactory(ISecurityDatabaseConnectionStringProvider connectionStringProvider, DatabaseEngine databaseEngine)
public SecurityContextFactory(ISecurityDatabaseConnectionStringProvider connectionStringProvider,
DatabaseEngine databaseEngine)
{
_connectionStringProvider = connectionStringProvider;
_databaseEngine = databaseEngine;
}

public ISecurityContext CreateContext()
public Type GetSecurityContextType()
{
if (_securityContextTypeByDatabaseEngine.TryGetValue(_databaseEngine, out Type contextType))
{
return Activator.CreateInstance(contextType, _connectionStringProvider.GetConnectionString()) as ISecurityContext;
return contextType;
}

throw new InvalidOperationException(
$"No SecurityContext defined for database type {_databaseEngine.DisplayName}");
}

public ISecurityContext CreateContext()
{
if (_databaseEngine == DatabaseEngine.SqlServer)
{
return Activator.CreateInstance(
GetSecurityContextType(),
new DbContextOptionsBuilder<SqlServerSecurityContext>()
.UseSqlServer(_connectionStringProvider.GetConnectionString())
.Options) as
ISecurityContext;
}

if (_databaseEngine == DatabaseEngine.Postgres)
{
return Activator.CreateInstance(
GetSecurityContextType(),
new DbContextOptionsBuilder<PostgresSecurityContext>()
.UseNpgsql(_connectionStringProvider.GetConnectionString())
.UseLowerCaseNamingConvention()
.Options) as
ISecurityContext;
}

throw new InvalidOperationException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
// See the LICENSE and NOTICES files in the project root for more information.

using Microsoft.EntityFrameworkCore;

namespace EdFi.Security.DataAccess.Contexts
{
public class SqlServerSecurityContext : SecurityContext
{
// The default behavior is appropriate for this sub-class.
public SqlServerSecurityContext(string connectionString) : base(connectionString) { }
public SqlServerSecurityContext(DbContextOptions options) : base(options) { }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@
</Choose>
<ItemGroup>
<PackageReference Include="Autofac.Extras.DynamicProxy" Version="6.0.1" />
<PackageReference Include="EntityFramework" Version="6.4.4" />
<PackageReference Include="EFCore.NamingConventions" Version="6.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.12" />
<PackageReference Include="Npgsql" Version="6.0.8" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.8" />
<PackageReference Include="System.Buffers" Version="4.5.1" />
<PackageReference Include="System.Memory" Version="4.5.5" />
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
using System;
using System.Collections.Generic;
// SPDX-License-Identifier: Apache-2.0
// Licensed to the Ed-Fi Alliance under one or more agreements.
// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
// See the LICENSE and NOTICES files in the project root for more information.

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
using Microsoft.EntityFrameworkCore;

namespace EdFi.Security.DataAccess.Models
{
[Index(nameof(ClaimSetResourceClaimActionId), nameof(AuthorizationStrategyId), IsUnique = true)]
public class ClaimSetResourceClaimActionAuthorizationStrategyOverrides
{
[Key]
Expand All @@ -15,14 +19,12 @@ public class ClaimSetResourceClaimActionAuthorizationStrategyOverrides
public int ClaimSetResourceClaimActionId { get; set; }

[Required]
[Index(IsUnique = true, Order = 1)]
[ForeignKey("ClaimSetResourceClaimActionId")]
public ClaimSetResourceClaimAction ClaimSetResourceClaimAction { get; set; }

public int AuthorizationStrategyId { get; set; }

[Required]
[Index(IsUnique = true, Order = 2)]
[ForeignKey("AuthorizationStrategyId")]
public AuthorizationStrategy AuthorizationStrategy { get; set; }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
// See the LICENSE and NOTICES files in the project root for more information.

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
// SPDX-License-Identifier: Apache-2.0
// Licensed to the Ed-Fi Alliance under one or more agreements.
// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
// See the LICENSE and NOTICES files in the project root for more information.

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;

namespace EdFi.Security.DataAccess.Models
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using EdFi.Common.Utils.Extensions;
using EdFi.Security.DataAccess.Contexts;
using EdFi.Security.DataAccess.Models;
using Microsoft.EntityFrameworkCore;
using Action = EdFi.Security.DataAccess.Models.Action;

namespace EdFi.Security.DataAccess.Repositories;
Expand Down Expand Up @@ -60,8 +60,9 @@ public List<ClaimSetResourceClaimAction> GetClaimSetResourceClaimActions()
var claimSetResourceClaimActions = context.ClaimSetResourceClaimActions.Include(csrc => csrc.Action)
.Include(csrc => csrc.ClaimSet)
.Include(csrc => csrc.ResourceClaim)
.Include(csrc => csrc.AuthorizationStrategyOverrides.Select(aso => aso.AuthorizationStrategy))
.ToList();
.Include(csrc => csrc.AuthorizationStrategyOverrides)
.ThenInclude(aso => aso.AuthorizationStrategy)
.ToList();

// Replace empty lists with null since some consumers expect it that way
claimSetResourceClaimActions.Where(csrc => csrc.AuthorizationStrategyOverrides.Count == 0)
Expand Down
30 changes: 0 additions & 30 deletions Application/EdFi.Security.DataAccess/Utils/ValidateDatabase.cs

This file was deleted.

Loading

0 comments on commit bdbc272

Please sign in to comment.