Skip to content

Commit

Permalink
[ODS-6110] Update EdFi.Admin.DataAccess to .NET 8 (#921)
Browse files Browse the repository at this point in the history
  • Loading branch information
axelmarquezh committed Jun 12, 2024
1 parent 55fe0c1 commit 345b17c
Show file tree
Hide file tree
Showing 22 changed files with 309 additions and 259 deletions.
4 changes: 0 additions & 4 deletions .github/workflows/Lib edFi.admin.dataaccess pullrequest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ jobs:

steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Setup .NET
uses: actions/setup-dotnet@607fce577a46308457984d59e4954e075820f10a # v3.0.3
with:
dotnet-version: 3.1.x
- name: build
run: |
.\build.githubactions.ps1 build -Configuration ${{ env.CONFIGURATION }} -InformationalVersion ${{ env.INFORMATIONAL_VERSION}} -BuildCounter ${{ github.run_number }} -BuildIncrementer ${{env.BUILD_INCREMENTER}} -Solution "Application/EdFi.Admin.DataAccess/EdFi.Admin.DataAccess.sln" -ProjectFile "Application/EdFi.Admin.DataAccess/EdFi.Admin.DataAccess.csproj"
Expand Down
4 changes: 0 additions & 4 deletions .github/workflows/Lib edFi.admin.dataaccess.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ jobs:

steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Setup .NET
uses: actions/setup-dotnet@607fce577a46308457984d59e4954e075820f10a # v3.0.3
with:
dotnet-version: 3.1.x
- name: build
run: |
.\build.githubactions.ps1 build -Configuration ${{ env.CONFIGURATION }} -InformationalVersion ${{ env.INFORMATIONAL_VERSION}} -BuildCounter ${{ github.run_number }} -BuildIncrementer ${{env.BUILD_INCREMENTER}} -Solution "Application/EdFi.Admin.DataAccess/EdFi.Admin.DataAccess.sln" -ProjectFile "Application/EdFi.Admin.DataAccess/EdFi.Admin.DataAccess.csproj"
Expand Down
30 changes: 17 additions & 13 deletions Application/EdFi.Admin.DataAccess/Contexts/IUsersContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,43 @@

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Threading;
using System.Threading.Tasks;
using EdFi.Admin.DataAccess.Models;
using Microsoft.EntityFrameworkCore;

namespace EdFi.Admin.DataAccess.Contexts
{
public interface IUsersContext : IDisposable
{
IDbSet<User> Users { get; set; }
DbSet<User> Users { get; set; }

IDbSet<ApiClient> Clients { get; set; }
DbSet<ApiClient> Clients { get; set; }

IDbSet<ClientAccessToken> ClientAccessTokens { get; set; }
DbSet<ClientAccessToken> ClientAccessTokens { get; set; }

IDbSet<Vendor> Vendors { get; set; }
DbSet<Vendor> Vendors { get; set; }

IDbSet<Application> Applications { get; set; }
DbSet<Application> Applications { get; set; }

IDbSet<Profile> Profiles { get; set; }
DbSet<Profile> Profiles { get; set; }

IDbSet<OdsInstance> OdsInstances { get; set; }
DbSet<OdsInstance> OdsInstances { get; set; }

IDbSet<OdsInstanceComponent> OdsInstanceComponents { get; set; }
DbSet<OdsInstanceComponent> OdsInstanceComponents { get; set; }

IDbSet<ApplicationEducationOrganization> ApplicationEducationOrganizations { get; set; }
DbSet<ApplicationEducationOrganization> ApplicationEducationOrganizations { get; set; }

IDbSet<VendorNamespacePrefix> VendorNamespacePrefixes { get; set; }
DbSet<VendorNamespacePrefix> VendorNamespacePrefixes { get; set; }

IDbSet<OwnershipToken> OwnershipToken { get; set; }
DbSet<OwnershipToken> OwnershipTokens { get; set; }

DbSet<ApiClientOwnershipToken> ApiClientOwnershipTokens { get; set; }


int SaveChanges();

Task<int> SaveChangesAsync();
Task<int> SaveChangesAsync(CancellationToken cancellationToken);

/// <summary>
/// Asynchronously executes a raw SQL statement with only a scalar result (e.g. row count).
Expand Down
66 changes: 15 additions & 51 deletions Application/EdFi.Admin.DataAccess/Contexts/PostgresUsersContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,68 +3,32 @@
// 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.Admin.DataAccess.Extensions;
using EdFi.Admin.DataAccess.Models;
using EdFi.Common;
using EdFi.Common.Utils.Extensions;
using Microsoft.EntityFrameworkCore;
using System.Linq;

namespace EdFi.Admin.DataAccess.Contexts
{
public class PostgresUsersContext : UsersContext
{
public PostgresUsersContext(string connectionString) : base(connectionString) { }
public PostgresUsersContext(DbContextOptions options)
: base(options) { }

protected override void ApplyProviderSpecificMappings(DbModelBuilder modelBuilder)
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// The column name in this linking table had to be shortened for Postgres
modelBuilder.Entity<ApiClient>()
.HasMany(t => t.ApplicationEducationOrganizations)
.WithMany(t => t.Clients)
.Map(
m =>
{
m.ToTable("ApiClientApplicationEducationOrganizations", "dbo");
m.MapLeftKey("ApiClient_ApiClientId");
m.MapRightKey("ApplicationEdOrg_ApplicationEdOrgId");
});
base.OnModelCreating(modelBuilder);

modelBuilder.Conventions.Add<ForeignKeyLowerCaseNamingConvention>();
modelBuilder.Conventions.Add<TableLowerCaseNamingConvention>();
modelBuilder.Model.GetEntityTypes().ForEach(
entityType =>
entityType.SetSchema("dbo"));

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);
modelBuilder.Model.GetEntityTypes().Single(e => e.ClrType.Name == nameof(ApiClientApplicationEducationOrganization))
.GetProperty("ApplicationEducationOrganizationId")
.SetColumnName("applicationedorg_applicationedorgid");

void PropertyNamesToLowerInvariant(EdmProperty property) => property.Name = property.Name.ToLowerInvariant();
}
modelBuilder.MakeDbObjectNamesLowercase();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
// 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.Admin.DataAccess.Contexts
{
public class SqlServerUsersContext : UsersContext
{
public SqlServerUsersContext(string connectionString) : base(connectionString) { }
public SqlServerUsersContext(DbContextOptions options) : base(options) { }
}
}
71 changes: 40 additions & 31 deletions Application/EdFi.Admin.DataAccess/Contexts/UsersContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,22 @@

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using EdFi.Admin.DataAccess.Extensions;
using EdFi.Admin.DataAccess.Models;
using EdFi.Admin.DataAccess.Utils;
using Microsoft.EntityFrameworkCore;

namespace EdFi.Admin.DataAccess.Contexts
{
public abstract class UsersContext : DbContext, IUsersContext
{

protected UsersContext(string connectionString)
: base(connectionString)
{
Database.SetInitializer(new ValidateDatabase<SqlServerUsersContext>());
Database.SetInitializer(new ValidateDatabase<PostgresUsersContext>());
}
protected UsersContext(DbContextOptions options)
: base(options) { }

public const string UserTableName = "Users";

public static string UserNameColumn
Expand All @@ -34,55 +33,65 @@ public static string UserIdColumn
get { return UserMemberName(x => x.UserId); }
}

public IDbSet<User> Users { get; set; }
public DbSet<User> Users { get; set; }

public IDbSet<ApiClient> Clients { get; set; }
public DbSet<ApiClient> Clients { get; set; }

public IDbSet<ClientAccessToken> ClientAccessTokens { get; set; }
public DbSet<ClientAccessToken> ClientAccessTokens { get; set; }

public IDbSet<Vendor> Vendors { get; set; }
public DbSet<Vendor> Vendors { get; set; }

public IDbSet<Application> Applications { get; set; }
public DbSet<Application> Applications { get; set; }

public IDbSet<Profile> Profiles { get; set; }
public DbSet<Profile> Profiles { get; set; }

public IDbSet<OdsInstance> OdsInstances { get; set; }
public DbSet<OdsInstance> OdsInstances { get; set; }

public IDbSet<OdsInstanceComponent> OdsInstanceComponents { get; set; }
public DbSet<OdsInstanceComponent> OdsInstanceComponents { get; set; }

//TODO: This should really be removed from being directly on the context. Application should own
//TODO: these instances, and deleting an application should delete the associated LEA's
public IDbSet<ApplicationEducationOrganization> ApplicationEducationOrganizations { get; set; }
public DbSet<ApplicationEducationOrganization> ApplicationEducationOrganizations { get; set; }

public IDbSet<VendorNamespacePrefix> VendorNamespacePrefixes { get; set; }
public DbSet<VendorNamespacePrefix> VendorNamespacePrefixes { get; set; }

public IDbSet<OwnershipToken> OwnershipToken { get; set; }
public DbSet<OwnershipToken> OwnershipTokens { get; set; }

public IDbSet<WebPagesUsersInRoles> UsersInRoles { get; set; }
public DbSet<ApiClientOwnershipToken> ApiClientOwnershipTokens { get; set; }

protected override void OnModelCreating(DbModelBuilder modelBuilder)
public DbSet<WebPagesUsersInRoles> UsersInRoles { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
ApplyProviderSpecificMappings(modelBuilder);
modelBuilder.Entity<ApiClient>()
.HasMany(t => t.ApplicationEducationOrganizations)
.WithMany(t => t.Clients)
.UsingEntity<ApiClientApplicationEducationOrganization>(
"ApiClientApplicationEducationOrganizations",
l =>
l.HasOne<ApplicationEducationOrganization>().WithMany().HasForeignKey(
"ApplicationEducationOrganizationId"),
r =>
r.HasOne<ApiClient>().WithMany().HasForeignKey("ApiClientId"));

modelBuilder.UseUnderscoredFkColumnNames();

modelBuilder.Model.FindEntityTypes(typeof(ApiClient)).First().GetProperty("CreatorOwnershipTokenId")
.SetColumnName("CreatorOwnershipTokenId_OwnershipTokenId");
}

/// <remarks>
/// Sub-classes should override this to provide database system-specific column and/or
/// table mappings: for example, if a linking table column in Postgres needs to map to a
/// name other than the default provided by Entity Framework.
/// </remarks>
protected virtual void ApplyProviderSpecificMappings(DbModelBuilder modelBuilder) { }

/// <inheritdoc />
public Task<int> ExecuteSqlCommandAsync(string sqlStatement, params object[] parameters)
{
return Database.ExecuteSqlCommandAsync(sqlStatement.ToLowerInvariant(), parameters);
return Database.ExecuteSqlInterpolatedAsync(
FormattableStringFactory.Create(sqlStatement.ToLowerInvariant(), parameters));
}

/// <inheritdoc />
public async Task<IReadOnlyList<TReturn>> ExecuteQueryAsync<TReturn>(string sqlStatement, params object[] parameters)
{
return await Database
.SqlQuery<TReturn>(sqlStatement.ToLowerInvariant(), parameters)
.SqlQueryRaw<TReturn>(sqlStatement.ToLowerInvariant(), parameters)
.ToListAsync();
}

Expand Down
34 changes: 31 additions & 3 deletions Application/EdFi.Admin.DataAccess/Contexts/UsersContextFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
using EdFi.Admin.DataAccess.Providers;
using EdFi.Common;
using EdFi.Common.Configuration;
using Microsoft.EntityFrameworkCore;

namespace EdFi.Admin.DataAccess.Contexts
{
public class UsersContextFactory : IUsersContextFactory
{
private readonly Dictionary<DatabaseEngine, Type> _usersContextTypeByDatabaseEngine = new Dictionary<DatabaseEngine, Type>
private readonly Dictionary<DatabaseEngine, Type> _usersContextTypeByDatabaseEngine = new()
{
{DatabaseEngine.SqlServer, typeof(SqlServerUsersContext)},
{DatabaseEngine.Postgres, typeof(PostgresUsersContext)}
Expand All @@ -28,12 +29,39 @@ public UsersContextFactory(IAdminDatabaseConnectionStringProvider connectionStri
_connectionStringsProvider = Preconditions.ThrowIfNull(connectionStringsProvider, nameof(connectionStringsProvider));
_databaseEngine = Preconditions.ThrowIfNull(databaseEngine, nameof(databaseEngine));
}
public Type GetUsersContextType()
{
if (_usersContextTypeByDatabaseEngine.TryGetValue(_databaseEngine, out Type contextType))
{
return contextType;
}

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

public IUsersContext CreateContext()
{
if (_usersContextTypeByDatabaseEngine.TryGetValue(_databaseEngine, out Type contextType))
if (_databaseEngine == DatabaseEngine.SqlServer)
{
return Activator.CreateInstance(
GetUsersContextType(),
new DbContextOptionsBuilder<SqlServerUsersContext>()
.UseLazyLoadingProxies()
.UseSqlServer(_connectionStringsProvider.GetConnectionString())
.Options) as
IUsersContext;
}

if (_databaseEngine == DatabaseEngine.Postgres)
{
return Activator.CreateInstance(contextType, _connectionStringsProvider.GetConnectionString()) as IUsersContext;
return Activator.CreateInstance(
GetUsersContextType(),
new DbContextOptionsBuilder<PostgresUsersContext>()
.UseLazyLoadingProxies()
.UseNpgsql(_connectionStringsProvider.GetConnectionString())
.Options) as
IUsersContext;
}

throw new InvalidOperationException(
Expand Down
14 changes: 8 additions & 6 deletions Application/EdFi.Admin.DataAccess/EdFi.Admin.DataAccess.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackageId>EdFi.Admin.DataAccess</PackageId>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
<AssemblyName>EdFi.Admin.DataAccess</AssemblyName>
<RootNamespace>EdFi.Admin.DataAccess</RootNamespace>
Expand All @@ -16,11 +16,13 @@
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="EdFi.Suite3.Common" Version="5.4.395" />
<PackageReference Include="EntityFramework" Version="6.4.4" />
<PackageReference Include="EntityFramework6.Npgsql" Version="6.4.3" />
<PackageReference Include="log4net" Version="2.0.13" />
<PackageReference Include="Npgsql" Version="6.0.11" />
<PackageReference Include="EdFi.Suite3.Common" Version="6.1.19" />
<PackageReference Include="log4net" Version="2.0.15" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="8.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.1" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<None Include="../../LICENSE.txt" Pack="true" PackagePath="LICENSE.txt" />
Expand Down
Loading

0 comments on commit 345b17c

Please sign in to comment.