diff --git a/Application/EdFi.Admin.DataAccess/Contexts/IUsersContext.cs b/Application/EdFi.Admin.DataAccess/Contexts/IUsersContext.cs index ad0379bef6..18f963d60b 100644 --- a/Application/EdFi.Admin.DataAccess/Contexts/IUsersContext.cs +++ b/Application/EdFi.Admin.DataAccess/Contexts/IUsersContext.cs @@ -4,132 +4,45 @@ // See the LICENSE and NOTICES files in the project root for more information. 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 Users { get; set; } + DbSet Users { get; set; } - IDbSet Clients { get; set; } + DbSet ApiClients { get; set; } - IDbSet ClientAccessTokens { get; set; } + DbSet ClientAccessTokens { get; set; } - IDbSet Vendors { get; set; } + DbSet Vendors { get; set; } - IDbSet Applications { get; set; } + DbSet Applications { get; set; } - IDbSet Profiles { get; set; } + DbSet Profiles { get; set; } - IDbSet OdsInstances { get; set; } + DbSet OdsInstances { get; set; } - IDbSet OdsInstanceContexts { get; set; } + DbSet OdsInstanceContexts { get; set; } - IDbSet OdsInstanceDerivatives { get; set; } + DbSet OdsInstanceDerivatives { get; set; } - IDbSet ApplicationEducationOrganizations { get; set; } + DbSet ApplicationEducationOrganizations { get; set; } - IDbSet VendorNamespacePrefixes { get; set; } + DbSet VendorNamespacePrefixes { get; set; } - IDbSet OwnershipTokens { get; set; } + DbSet OwnershipTokens { get; set; } + + DbSet ApiClientOdsInstances { get; set; } DbSet ApiClientOwnershipTokens { get; set; } - DbSet ApiClientOdsInstances { get; set; } - int SaveChanges(); - Task SaveChangesAsync(); - - /// - /// Asynchronously executes a raw SQL statement with only a scalar result (e.g. row count). - /// - /// Query to execute, optionally containing parameter strings using @ symbol token - /// Optional parameters - /// Statement result (row count by default) - /// - /// - /// No parameters: - /// - /// - /// result = await _usersContext.ExecuteQueryAsync(sqlCommand); - /// ]]> - /// - /// - /// Single parameter, @p0. The name does not matter; @p0 is a good standard to follow to indicate to the reader that it is the first parameter. - /// - /// - /// @p0"; - /// IReadOnlyList result = await _usersContext.ExecuteQueryAsync(sqlCommand, fieldTwoLowerLimit); - /// ]]> - /// - /// - /// Two parameters, second one for a CreateDate field that we're not going to return. - /// - /// - /// @p0 AND CreateDate < '@p1'"; - /// IReadOnlyList result = await _usersContext.ExecuteQueryAsync(sqlCommand, fieldTwoLowerLimit, createDateUpperLimit); - /// ]]> - /// - /// - Task ExecuteSqlCommandAsync(string sqlStatement, params object[] parameters); - - /// - /// Asynchronously executes a raw SQL query and maps the results to an object of type . - /// - /// Any class with properties matching the column names in the query - /// Query to execute, optionally containing parameter strings using @ symbol token - /// Optional parameters - /// Readonly list of - /// - /// - /// Given this return entity: - /// - /// - /// public class Something { public string FieldOne { get; set; } public int FieldTwo { get; set; } } - /// - /// - /// No parameters: - /// - /// - /// result = await _usersContext.ExecuteQueryAsync(sqlCommand); - /// ]]> - /// - /// - /// Single parameter, @p0. The name does not matter; @p0 is a good standard to follow to indicate to the reader that it is the first parameter. - /// - /// - /// @p0"; - /// IReadOnlyList result = await _usersContext.ExecuteQueryAsync(sqlCommand, fieldTwoLowerLimit); - /// ]]> - /// - /// - /// Two parameters, second one for a CreateDate field that we're not going to return. - /// - /// - /// @p0 AND CreateDate < '@p1'"; - /// IReadOnlyList result = await _usersContext.ExecuteQueryAsync(sqlCommand, fieldTwoLowerLimit, createDateUpperLimit); - /// ]]> - /// - /// - Task> ExecuteQueryAsync(string sqlStatement, params object[] parameters); + Task SaveChangesAsync(CancellationToken cancellationToken); } } diff --git a/Application/EdFi.Admin.DataAccess/Contexts/PostgresUsersContext.cs b/Application/EdFi.Admin.DataAccess/Contexts/PostgresUsersContext.cs index 09622e916b..f7699c851b 100644 --- a/Application/EdFi.Admin.DataAccess/Contexts/PostgresUsersContext.cs +++ b/Application/EdFi.Admin.DataAccess/Contexts/PostgresUsersContext.cs @@ -3,68 +3,37 @@ // 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 System.Linq; +using EdFi.Admin.DataAccess.Extensions; using EdFi.Admin.DataAccess.Models; -using EdFi.Common; using EdFi.Common.Utils.Extensions; +using Microsoft.EntityFrameworkCore; 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() - .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(); - modelBuilder.Conventions.Add(); + modelBuilder.Model.GetEntityTypes().ForEach( + entityType => + entityType.SetSchema("dbo")); - modelBuilder.Properties().Configure(c => c.HasColumnName(c.ClrPropertyInfo.Name.ToLowerInvariant())); - } - - private class TableLowerCaseNamingConvention : IStoreModelConvention - { - 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 - { - public void Apply(AssociationType association, DbModel model) - { - Preconditions.ThrowIfNull(association, nameof(association)); - Preconditions.ThrowIfNull(model, nameof(model)); - - if (!association.IsForeignKey) - { - return; - } + modelBuilder.Model.GetEntityTypes().Single(e => e.ClrType.Name == nameof(ApiClientApplicationEducationOrganization)) + .GetProperty("ApplicationEducationOrganizationId") + .SetColumnName("applicationedorg_applicationedorgid"); - association.Constraint.FromProperties.ForEach(PropertyNamesToLowerInvariant); - association.Constraint.ToProperties.ForEach(PropertyNamesToLowerInvariant); + modelBuilder + .Entity() + .Property(e => e.ProfileDefinition) + .HasColumnType("xml"); - void PropertyNamesToLowerInvariant(EdmProperty property) => property.Name = property.Name.ToLowerInvariant(); - } + modelBuilder.MakeDbObjectNamesLowercase(); } } } diff --git a/Application/EdFi.Admin.DataAccess/Contexts/SqlServerUsersContext.cs b/Application/EdFi.Admin.DataAccess/Contexts/SqlServerUsersContext.cs index 0e777b3eb9..61200628e0 100644 --- a/Application/EdFi.Admin.DataAccess/Contexts/SqlServerUsersContext.cs +++ b/Application/EdFi.Admin.DataAccess/Contexts/SqlServerUsersContext.cs @@ -3,25 +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 System.Data.Entity; -using EdFi.Admin.DataAccess.Models; +using Microsoft.EntityFrameworkCore; namespace EdFi.Admin.DataAccess.Contexts { public class SqlServerUsersContext : UsersContext { - public SqlServerUsersContext(string connectionString) : base(connectionString) { } - - protected override void ApplyProviderSpecificMappings(DbModelBuilder modelBuilder) - { - modelBuilder.Entity() - .HasMany(t => t.ApplicationEducationOrganizations) - .WithMany(t => t.Clients) - .Map( - m => - { - m.ToTable("ApiClientApplicationEducationOrganizations", "dbo"); - }); - } + public SqlServerUsersContext(DbContextOptions options) + : base(options) { } } } diff --git a/Application/EdFi.Admin.DataAccess/Contexts/UsersContext.cs b/Application/EdFi.Admin.DataAccess/Contexts/UsersContext.cs index 9a422f6c40..3319ea6bbc 100644 --- a/Application/EdFi.Admin.DataAccess/Contexts/UsersContext.cs +++ b/Application/EdFi.Admin.DataAccess/Contexts/UsersContext.cs @@ -4,26 +4,23 @@ // See the LICENSE and NOTICES files in the project root for more information. 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()); - Database.SetInitializer(new ValidateDatabase()); - } public const string UserTableName = "Users"; + protected UsersContext(DbContextOptions options) + : base(options) { } + public static string UserNameColumn { get { return UserMemberName(x => x.Email); } @@ -34,62 +31,67 @@ public static string UserIdColumn get { return UserMemberName(x => x.UserId); } } - public IDbSet Users { get; set; } + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasMany(t => t.ApplicationEducationOrganizations) + .WithMany(t => t.ApiClients) + .UsingEntity( + "ApiClientApplicationEducationOrganizations", + l => + l.HasOne().WithMany().HasForeignKey( + "ApplicationEducationOrganizationId"), + r => + r.HasOne().WithMany().HasForeignKey("ApiClientId")); + + modelBuilder.Entity() + .HasMany(a => a.Profiles) + .WithMany(a => a.Applications) + .UsingEntity("ProfileApplications"); + + modelBuilder.UseUnderscoredFkColumnNames(); + + modelBuilder.Model.FindEntityTypes(typeof(ApiClient)).First().GetProperty("CreatorOwnershipTokenId") + .SetColumnName("CreatorOwnershipTokenId_OwnershipTokenId"); + } + + public DbSet Users { get; set; } - public IDbSet Clients { get; set; } + public DbSet ApiClients { get; set; } - public IDbSet ClientAccessTokens { get; set; } + public DbSet ClientAccessTokens { get; set; } - public IDbSet Vendors { get; set; } + public DbSet Vendors { get; set; } - public IDbSet Applications { get; set; } + public DbSet Applications { get; set; } - public IDbSet Profiles { get; set; } + public DbSet Profiles { get; set; } - public IDbSet OdsInstances { get; set; } + public DbSet ApiClientOwnershipTokens { get; set; } - public IDbSet OdsInstanceContexts { get; set; } + public DbSet OdsInstances { get; set; } - public IDbSet OdsInstanceDerivatives { get; set; } + public DbSet OdsInstanceContexts { get; set; } + + public DbSet OdsInstanceDerivatives { 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 ApplicationEducationOrganizations { get; set; } + public DbSet ApplicationEducationOrganizations { get; set; } - public IDbSet VendorNamespacePrefixes { get; set; } + public DbSet VendorNamespacePrefixes { get; set; } - public IDbSet OwnershipTokens { get; set; } - - public DbSet ApiClientOwnershipTokens { get; set; } + public DbSet OwnershipTokens { get; set; } public DbSet ApiClientOdsInstances { get; set; } - public IDbSet UsersInRoles { get; set; } - - protected override void OnModelCreating(DbModelBuilder modelBuilder) - { - ApplyProviderSpecificMappings(modelBuilder); - } - - /// - /// 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. - /// - protected virtual void ApplyProviderSpecificMappings(DbModelBuilder modelBuilder) { } + public DbSet UsersInRoles { get; set; } /// public Task ExecuteSqlCommandAsync(string sqlStatement, params object[] parameters) { - return Database.ExecuteSqlCommandAsync(sqlStatement.ToLowerInvariant(), parameters); - } - - /// - public async Task> ExecuteQueryAsync(string sqlStatement, params object[] parameters) - { - return await Database - .SqlQuery(sqlStatement.ToLowerInvariant(), parameters) - .ToListAsync(); + return Database.ExecuteSqlInterpolatedAsync( + FormattableStringFactory.Create(sqlStatement.ToLowerInvariant(), parameters)); } private static string UserMemberName(Expression> emailExpression) diff --git a/Application/EdFi.Admin.DataAccess/Contexts/UsersContextFactory.cs b/Application/EdFi.Admin.DataAccess/Contexts/UsersContextFactory.cs index 7aa636ae0a..88b0e1e268 100644 --- a/Application/EdFi.Admin.DataAccess/Contexts/UsersContextFactory.cs +++ b/Application/EdFi.Admin.DataAccess/Contexts/UsersContextFactory.cs @@ -8,32 +8,61 @@ 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 IAdminDatabaseConnectionStringProvider _connectionStringsProvider; + + private readonly DatabaseEngine _databaseEngine; private readonly Dictionary _usersContextTypeByDatabaseEngine = new() { - {DatabaseEngine.SqlServer, typeof(SqlServerUsersContext)}, - {DatabaseEngine.Postgres, typeof(PostgresUsersContext)} + { DatabaseEngine.SqlServer, typeof(SqlServerUsersContext) }, + { DatabaseEngine.Postgres, typeof(PostgresUsersContext) } }; - private readonly DatabaseEngine _databaseEngine; - - private readonly IAdminDatabaseConnectionStringProvider _connectionStringsProvider; - - public UsersContextFactory(IAdminDatabaseConnectionStringProvider connectionStringsProvider, DatabaseEngine databaseEngine) + public UsersContextFactory(IAdminDatabaseConnectionStringProvider connectionStringsProvider, + DatabaseEngine databaseEngine) { _connectionStringsProvider = Preconditions.ThrowIfNull(connectionStringsProvider, nameof(connectionStringsProvider)); - _databaseEngine = Preconditions.ThrowIfNull(databaseEngine, nameof(databaseEngine)); + _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() + .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() + .UseLazyLoadingProxies() + .UseNpgsql(_connectionStringsProvider.GetConnectionString()) + .Options) as + IUsersContext; } throw new InvalidOperationException( diff --git a/Application/EdFi.Admin.DataAccess/DbConfigurations/DatabaseEngineDbConfiguration.cs b/Application/EdFi.Admin.DataAccess/DbConfigurations/DatabaseEngineDbConfiguration.cs deleted file mode 100644 index 3b088b12d9..0000000000 --- a/Application/EdFi.Admin.DataAccess/DbConfigurations/DatabaseEngineDbConfiguration.cs +++ /dev/null @@ -1,46 +0,0 @@ -// 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 EdFi.Common.Configuration; -using Npgsql; -using System.Data.Entity; -using System.Data.Entity.Infrastructure; -using System.Data.Entity.SqlServer; -using System.Data.SqlClient; - -namespace EdFi.Admin.DataAccess.DbConfigurations -{ - public class DatabaseEngineDbConfiguration : DbConfiguration - { - public DatabaseEngineDbConfiguration(DatabaseEngine databaseEngine) - { - if (databaseEngine == DatabaseEngine.SqlServer) - { - SetProviderFactory( - providerInvariantName: SqlProviderServices.ProviderInvariantName, - providerFactory: SqlClientFactory.Instance); - - SetProviderServices( - providerInvariantName: SqlProviderServices.ProviderInvariantName, - provider: SqlProviderServices.Instance); - SetDefaultConnectionFactory(connectionFactory: new SqlConnectionFactory()); - } - else if (databaseEngine == DatabaseEngine.Postgres) - { - const string name = "Npgsql"; - - SetProviderFactory( - providerInvariantName: name, - providerFactory: NpgsqlFactory.Instance); - - SetProviderServices( - providerInvariantName: name, - provider: NpgsqlServices.Instance); - - SetDefaultConnectionFactory(connectionFactory: new NpgsqlConnectionFactory()); - } - } - } -} diff --git a/Application/EdFi.Admin.DataAccess/EdFi.Admin.DataAccess.csproj b/Application/EdFi.Admin.DataAccess/EdFi.Admin.DataAccess.csproj index e1d8cce3d1..3494c3f330 100644 --- a/Application/EdFi.Admin.DataAccess/EdFi.Admin.DataAccess.csproj +++ b/Application/EdFi.Admin.DataAccess/EdFi.Admin.DataAccess.csproj @@ -27,9 +27,13 @@ - - + + + + + + diff --git a/Application/EdFi.Admin.DataAccess/Extensions/DbContextExtensions.cs b/Application/EdFi.Admin.DataAccess/Extensions/DbContextExtensions.cs index 39831ebe6f..21114f919a 100644 --- a/Application/EdFi.Admin.DataAccess/Extensions/DbContextExtensions.cs +++ b/Application/EdFi.Admin.DataAccess/Extensions/DbContextExtensions.cs @@ -3,41 +3,17 @@ // 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.Objects; -using System.Data.Entity.Infrastructure; -using System.Text.RegularExpressions; +using System.Linq; +using Microsoft.EntityFrameworkCore; namespace EdFi.Admin.DataAccess.Extensions { public static class DbContextExtensions { - public static string GetTableName(this DbContext context) + public static void DeleteAll(this DbContext context) where T : class { - var objectContext = ((IObjectContextAdapter) context).ObjectContext; - - return objectContext.GetTableName(); - } - - public static string GetTableName(this ObjectContext context) - where T : class - { - var sql = context.CreateObjectSet() - .ToTraceString(); - - var regex = new Regex("FROM (?.*) AS"); - var match = regex.Match(sql); - - var table = match.Groups["table"] - .Value; - - return table; - } - - public static void DeleteAll(this DbContext context) where T : class - { - foreach (var p in context.Set()) + foreach (var p in context.Set().ToList()) { context.Entry(p).State = EntityState.Deleted; } diff --git a/Application/EdFi.Admin.DataAccess/Extensions/ModelBuilderExtensions.cs b/Application/EdFi.Admin.DataAccess/Extensions/ModelBuilderExtensions.cs new file mode 100644 index 0000000000..2f0aa846b1 --- /dev/null +++ b/Application/EdFi.Admin.DataAccess/Extensions/ModelBuilderExtensions.cs @@ -0,0 +1,45 @@ +// 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.Linq; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata; + +namespace EdFi.Admin.DataAccess.Extensions; + +public static class ModelBuilderExtensions +{ + public static void MakeDbObjectNamesLowercase(this ModelBuilder modelBuilder) + { + foreach (var entityType in modelBuilder.Model.GetEntityTypes()) + { + if (entityType.GetTableName() is not { } tableName) + { + continue; + } + + entityType.SetTableName(tableName.ToLowerInvariant()); + + foreach (var property in entityType.GetProperties()) + { + property.SetColumnName(property.GetColumnName().ToLowerInvariant()); + } + } + } + + // EF Core does not recognize the _ convention + // for FK column names, so we update column names in the model metadata to match the database + public static void UseUnderscoredFkColumnNames(this ModelBuilder modelBuilder) + { + foreach (var foreignKey in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys())) + { + foreach (IMutableProperty foreignKeyProperty in foreignKey.Properties) + { + foreignKeyProperty.SetColumnName( + $"{foreignKey.GetNavigation(true)?.TargetEntityType.ShortName() ?? foreignKey.PrincipalKey.DeclaringEntityType.ShortName()}_{foreignKey.PrincipalKey.Properties.Single().Name}"); + } + } + } +} diff --git a/Application/EdFi.Admin.DataAccess/Models/AccountModels.cs b/Application/EdFi.Admin.DataAccess/Models/AccountModels.cs index f2a833fced..12e820c7ec 100644 --- a/Application/EdFi.Admin.DataAccess/Models/AccountModels.cs +++ b/Application/EdFi.Admin.DataAccess/Models/AccountModels.cs @@ -40,9 +40,12 @@ public User() public ApiClient AddSandboxClient(string name, SandboxType sandboxType, string key, string secret) { var client = new ApiClient(true) - { - Name = name, IsApproved = true, UseSandbox = true, SandboxType = sandboxType - }; + { + Name = name, + IsApproved = true, + UseSandbox = true, + SandboxType = sandboxType + }; if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(secret)) { @@ -60,7 +63,7 @@ public static User Create(string userEmail, string userName, Vendor vendor = nul { Email = userEmail, FullName = userName, - Vendor = vendor + Vendor = vendor }; } } diff --git a/Application/EdFi.Admin.DataAccess/Models/ApiClient.cs b/Application/EdFi.Admin.DataAccess/Models/ApiClient.cs index 8c725d5b2d..0089e6d3df 100644 --- a/Application/EdFi.Admin.DataAccess/Models/ApiClient.cs +++ b/Application/EdFi.Admin.DataAccess/Models/ApiClient.cs @@ -44,6 +44,7 @@ public ApiClient(bool generateKey = false) /// /// Numeric Identifier /// + [Key] public int ApiClientId { get; set; } /// @@ -127,21 +128,25 @@ public string SandboxTypeName /// /// Have a reference to OwnershipToken table ownershiptokenid for specific apiclient. /// - public virtual OwnershipToken CreatorOwnershipTokenId { get; set; } - + public virtual OwnershipToken CreatorOwnershipToken { get; set; } + + [Column("CreatorOwnershipTokenId_OwnershipTokenId")] + public short? CreatorOwnershipTokenId { get; set; } + /// /// Fully namespaced URI reference to the StudentIdentificationSystemDescriptor value to use for identification mapping /// [StringLength(306)] public string StudentIdentificationSystemDescriptor { get; set; } - + public virtual Application Application { get; set; } - + + public virtual User User { get; set; } - public ICollection ApplicationEducationOrganizations { get; set; } + public virtual ICollection ApplicationEducationOrganizations { get; set; } - public List ClientAccessTokens { get; set; } + public virtual List ClientAccessTokens { get; set; } /// /// Key-value store of EdOrg and Domain Connection information @@ -150,6 +155,7 @@ public string SandboxTypeName /// EdOrg is the key, Domain Connection information is the value. /// The end-user should never see the Data Connection information /// + [NotMapped] public Dictionary Domains { get; set; } /// diff --git a/Application/EdFi.Admin.DataAccess/Models/ApiClientApplicationEducationOrganization.cs b/Application/EdFi.Admin.DataAccess/Models/ApiClientApplicationEducationOrganization.cs new file mode 100644 index 0000000000..1a66756c50 --- /dev/null +++ b/Application/EdFi.Admin.DataAccess/Models/ApiClientApplicationEducationOrganization.cs @@ -0,0 +1,22 @@ +// 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.Schema; +using Microsoft.EntityFrameworkCore; + +namespace EdFi.Admin.DataAccess.Models +{ + [PrimaryKey("ApiClientId", "ApplicationEducationOrganizationId")] + [Index("ApiClientId")] + [Index("ApplicationEducationOrganizationId")] + public class ApiClientApplicationEducationOrganization + { + [Column("ApiClient_ApiClientId")] + public int ApiClientId { get; set; } + + [Column("ApplicationEducationOrganization_ApplicationEducationOrganizationId")] + public int ApplicationEducationOrganizationId { get; set; } + } +} diff --git a/Application/EdFi.Admin.DataAccess/Models/ApiClientOdsInstance.cs b/Application/EdFi.Admin.DataAccess/Models/ApiClientOdsInstance.cs index f5fe52e2ce..2645829533 100644 --- a/Application/EdFi.Admin.DataAccess/Models/ApiClientOdsInstance.cs +++ b/Application/EdFi.Admin.DataAccess/Models/ApiClientOdsInstance.cs @@ -3,14 +3,17 @@ // 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.Schema; using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Microsoft.EntityFrameworkCore; namespace EdFi.Admin.DataAccess.Models { /// /// Class representing the association of an Api Client with an Ods Instance /// + [Index("ApiClientId")] + [Index("OdsInstanceId")] public class ApiClientOdsInstance { /// @@ -19,13 +22,9 @@ public class ApiClientOdsInstance [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ApiClientOdsInstanceId { get; set; } - - [Required] - [Index(IsUnique = true, Order = 1)] - public ApiClient ApiClient { get; set; } - - [Required] - [Index(IsUnique = true, Order = 2)] - public OdsInstance OdsInstance { get; set; } + + public virtual ApiClient ApiClient { get; set; } + + public virtual OdsInstance OdsInstance { get; set; } } } diff --git a/Application/EdFi.Admin.DataAccess/Models/ApiClientOwnershipToken.cs b/Application/EdFi.Admin.DataAccess/Models/ApiClientOwnershipToken.cs index 9b1bd8ca84..ee26d78b8e 100644 --- a/Application/EdFi.Admin.DataAccess/Models/ApiClientOwnershipToken.cs +++ b/Application/EdFi.Admin.DataAccess/Models/ApiClientOwnershipToken.cs @@ -20,13 +20,11 @@ public class ApiClientOwnershipToken [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ApiClientOwnershipTokenId { get; set; } - - [Required] - [Index(IsUnique = true, Order = 2)] - public OwnershipToken OwnershipToken { get; set; } - - [Required] - [Index(IsUnique = true, Order = 1)] - public ApiClient ApiClient { get; set; } + + [Column("OwnershipToken_OwnershipTokenId")] + public int OwnershipTokenId { get; set; } + + [Column("ApiClient_ApiClientId")] + public int ApiClientId { get; set; } } } diff --git a/Application/EdFi.Admin.DataAccess/Models/Application.cs b/Application/EdFi.Admin.DataAccess/Models/Application.cs index 360de595de..b0e095eb38 100644 --- a/Application/EdFi.Admin.DataAccess/Models/Application.cs +++ b/Application/EdFi.Admin.DataAccess/Models/Application.cs @@ -45,7 +45,7 @@ public ApplicationEducationOrganization CreateApplicationEducationOrganization(l { EducationOrganizationId = educationOrganizationId, Application = this, - Clients = ApiClients + ApiClients = ApiClients }; } } diff --git a/Application/EdFi.Admin.DataAccess/Models/ApplicationEducationOrganization.cs b/Application/EdFi.Admin.DataAccess/Models/ApplicationEducationOrganization.cs index 185c924fd8..626c502d86 100644 --- a/Application/EdFi.Admin.DataAccess/Models/ApplicationEducationOrganization.cs +++ b/Application/EdFi.Admin.DataAccess/Models/ApplicationEducationOrganization.cs @@ -10,21 +10,21 @@ namespace EdFi.Admin.DataAccess.Models { - public sealed class ApplicationEducationOrganization + public class ApplicationEducationOrganization { public ApplicationEducationOrganization() { - Clients = new Collection(); + ApiClients = new Collection(); } [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ApplicationEducationOrganizationId { get; set; } - public Application Application { get; set; } + public virtual Application Application { get; set; } public long EducationOrganizationId { get; set; } - public ICollection Clients { get; set; } + public virtual ICollection ApiClients { get; set; } } } diff --git a/Application/EdFi.Admin.DataAccess/Models/ClientAccessToken.cs b/Application/EdFi.Admin.DataAccess/Models/ClientAccessToken.cs index 307f53095b..377c3f5b61 100644 --- a/Application/EdFi.Admin.DataAccess/Models/ClientAccessToken.cs +++ b/Application/EdFi.Admin.DataAccess/Models/ClientAccessToken.cs @@ -4,6 +4,7 @@ // See the LICENSE and NOTICES files in the project root for more information. using System; +using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace EdFi.Admin.DataAccess.Models @@ -21,7 +22,8 @@ public ClientAccessToken(TimeSpan lifespan) Expiration = DateTime.UtcNow.Add(lifespan); Duration = lifespan; } - + + [Key] public Guid Id { get @@ -36,9 +38,9 @@ public Guid Id set { _id = value; } } - public ApiClient ApiClient { get; set; } + public virtual ApiClient ApiClient { get; set; } - public DateTime Expiration { get; set; } + public virtual DateTime Expiration { get; set; } [NotMapped] public TimeSpan Duration { get; } diff --git a/Application/EdFi.Admin.DataAccess/Models/OAuthTokenClient.cs b/Application/EdFi.Admin.DataAccess/Models/OAuthTokenClient.cs deleted file mode 100644 index 9729f8c6d4..0000000000 --- a/Application/EdFi.Admin.DataAccess/Models/OAuthTokenClient.cs +++ /dev/null @@ -1,34 +0,0 @@ -// 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; - -namespace EdFi.Admin.DataAccess.Models -{ - public class OAuthTokenClient - { - public string Key { get; set; } - - public bool UseSandbox { get; set; } - - public string StudentIdentificationSystemDescriptor { get; set; } - - public long? EducationOrganizationId { get; set; } - - public string ClaimSetName { get; set; } - - public string NamespacePrefix { get; set; } - - public string ProfileName { get; set; } - - public short? CreatorOwnershipTokenId { get; set; } - - public short? OwnershipTokenId { get; set; } - - public DateTime Expiration { get; set; } - - public int ApiClientId { get; set; } - } -} diff --git a/Application/EdFi.Admin.DataAccess/Models/OdsInstance.cs b/Application/EdFi.Admin.DataAccess/Models/OdsInstance.cs index 32ab3022b0..f8f86a1d8a 100644 --- a/Application/EdFi.Admin.DataAccess/Models/OdsInstance.cs +++ b/Application/EdFi.Admin.DataAccess/Models/OdsInstance.cs @@ -41,8 +41,8 @@ public OdsInstance() [Required] public string ConnectionString { get; set; } - public ICollection OdsInstanceContexts { get; set; } + public virtual ICollection OdsInstanceContexts { get; set; } - public ICollection OdsInstanceDerivatives { get; set; } + public virtual ICollection OdsInstanceDerivatives { get; set; } } } diff --git a/Application/EdFi.Admin.DataAccess/Models/OdsInstanceDerivative.cs b/Application/EdFi.Admin.DataAccess/Models/OdsInstanceDerivative.cs index 3313ff2c83..cd9f5c0e52 100644 --- a/Application/EdFi.Admin.DataAccess/Models/OdsInstanceDerivative.cs +++ b/Application/EdFi.Admin.DataAccess/Models/OdsInstanceDerivative.cs @@ -14,7 +14,7 @@ public class OdsInstanceDerivative [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int OdsInstanceDerivativeId { get; set; } - public virtual OdsInstance OdsInstance {get; set; } + public virtual OdsInstance OdsInstance { get; set; } /// /// The type of derivative (e.g. "Snapshot") diff --git a/Application/EdFi.Admin.DataAccess/Models/OwnershipToken.cs b/Application/EdFi.Admin.DataAccess/Models/OwnershipToken.cs index a3c0da4519..92f7829f41 100644 --- a/Application/EdFi.Admin.DataAccess/Models/OwnershipToken.cs +++ b/Application/EdFi.Admin.DataAccess/Models/OwnershipToken.cs @@ -7,7 +7,6 @@ using System.Collections.ObjectModel; using System.ComponentModel.DataAnnotations; - namespace EdFi.Admin.DataAccess.Models { /// @@ -31,7 +30,6 @@ public OwnershipToken() /// [StringLength(50)] public string Description { get; set; } - public ICollection ApiClients { get; set; } - + public virtual ICollection ApiClients { get; set; } } } diff --git a/Application/EdFi.Admin.DataAccess/Models/ProfileApplication.cs b/Application/EdFi.Admin.DataAccess/Models/ProfileApplication.cs new file mode 100644 index 0000000000..52c2bd963b --- /dev/null +++ b/Application/EdFi.Admin.DataAccess/Models/ProfileApplication.cs @@ -0,0 +1,19 @@ +// 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 Microsoft.EntityFrameworkCore; + +namespace EdFi.Admin.DataAccess.Models +{ + [PrimaryKey("ApplicationId", "ProfileId")] + [Index("ApplicationId")] + [Index("ProfileId")] + public class ProfileApplication + { + public Profile Profile { get; set; } + + public Application Application { get; set; } + } +} diff --git a/Application/EdFi.Admin.DataAccess/Models/Vendor.cs b/Application/EdFi.Admin.DataAccess/Models/Vendor.cs index 5bbf84437f..f95c9ca5af 100644 --- a/Application/EdFi.Admin.DataAccess/Models/Vendor.cs +++ b/Application/EdFi.Admin.DataAccess/Models/Vendor.cs @@ -46,7 +46,7 @@ public Application CreateApplication(string applicationName, string claimSetName public static Vendor Create(string vendorName, IEnumerable namespacePrefixes) { - var vendor = new Vendor {VendorName = vendorName}; + var vendor = new Vendor { VendorName = vendorName }; foreach (string namespacePrefix in namespacePrefixes) { diff --git a/Application/EdFi.Admin.DataAccess/Models/VendorNamespacePrefix.cs b/Application/EdFi.Admin.DataAccess/Models/VendorNamespacePrefix.cs index 627b9591f7..1bc8adbde4 100644 --- a/Application/EdFi.Admin.DataAccess/Models/VendorNamespacePrefix.cs +++ b/Application/EdFi.Admin.DataAccess/Models/VendorNamespacePrefix.cs @@ -8,14 +8,14 @@ namespace EdFi.Admin.DataAccess.Models { - public sealed class VendorNamespacePrefix + public class VendorNamespacePrefix { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int VendorNamespacePrefixId { get; set; } [Required] - public Vendor Vendor { get; set; } + public virtual Vendor Vendor { get; set; } [Required] [StringLength(255)] diff --git a/Application/EdFi.Admin.DataAccess/Repositories/ClientAppRepo.cs b/Application/EdFi.Admin.DataAccess/Repositories/ClientAppRepo.cs index 3728bb5339..d4d81fd819 100644 --- a/Application/EdFi.Admin.DataAccess/Repositories/ClientAppRepo.cs +++ b/Application/EdFi.Admin.DataAccess/Repositories/ClientAppRepo.cs @@ -5,16 +5,15 @@ using System; using System.Collections.Generic; -using System.Data.Entity; -using System.Data.Entity.Migrations; using System.Linq; using System.Threading.Tasks; using EdFi.Admin.DataAccess.Contexts; using EdFi.Admin.DataAccess.Extensions; -using Microsoft.Extensions.Configuration; using EdFi.Admin.DataAccess.Models; using EdFi.Common; using log4net; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; namespace EdFi.Admin.DataAccess.Repositories { @@ -22,16 +21,13 @@ public class ClientAppRepo : IClientAppRepo { private const int DefaultDuration = 60; private readonly IUsersContextFactory _contextFactory; - - private readonly ILog _logger = LogManager.GetLogger(typeof(ClientAppRepo)); - private readonly Lazy _duration; - private readonly Lazy _defaultOperationalContextUri; private readonly Lazy _defaultAppName; private readonly Lazy _defaultClaimSetName; + private readonly Lazy _defaultOperationalContextUri; + private readonly Lazy _duration; + private readonly ILog _logger = LogManager.GetLogger(typeof(ClientAppRepo)); - public ClientAppRepo( - IUsersContextFactory contextFactory, - IConfigurationRoot config) + public ClientAppRepo(IUsersContextFactory contextFactory, IConfigurationRoot config) { _contextFactory = Preconditions.ThrowIfNull(contextFactory, nameof(contextFactory)); Preconditions.ThrowIfNull(config, nameof(config)); @@ -41,9 +37,9 @@ public ClientAppRepo( { // Get the config value, defaulting to 1 hour if (!int.TryParse( - config.GetSection("BearerTokenTimeoutMinutes") - .Value, - out int duration)) + config.GetSection("BearerTokenTimeoutMinutes") + .Value, + out int duration)) { duration = DefaultDuration; } @@ -64,22 +60,6 @@ public ClientAppRepo( .Value); } - private Profile GetOrCreateProfile(string profileName, string profileDefinition) - { - using (var context = _contextFactory.CreateContext()) - { - var profiles = context.Profiles.FirstOrDefault(s => s.ProfileName == profileName); - - if (profiles == null) - { - context.Profiles.Add(new Profile { ProfileName = profileName ,ProfileDefinition = profileDefinition }); - context.SaveChanges(); - } - - return context.Profiles.FirstOrDefault(s => s.ProfileName == profileName); - } - } - public void CreateProfilesWithProfileDefinition(List profiles) { using (var context = _contextFactory.CreateContext()) @@ -90,27 +70,16 @@ public void CreateProfilesWithProfileDefinition(List profiles) if (profileExists == null) { - context.Profiles.Add(new Profile { ProfileName = profile.ProfileName, ProfileDefinition = profile.ProfileDefinition }); - + context.Profiles.Add( + new Profile + { + ProfileName = profile.ProfileName, + ProfileDefinition = profile.ProfileDefinition + }); } } - context.SaveChanges(); - } - } - - private OwnershipToken GetOrCreateOwnershipToken(string ownershipToken) - { - using (var context = _contextFactory.CreateContext()) - { - var ownershipTokens = context.OwnershipTokens.FirstOrDefault(s => s.Description == ownershipToken); - - if (ownershipTokens == null) - { - context.OwnershipTokens.Add(new OwnershipToken { Description = ownershipToken }); - context.SaveChanges(); - } - return context.OwnershipTokens.FirstOrDefault(s => s.Description == ownershipToken); + context.SaveChanges(); } } @@ -126,7 +95,7 @@ public void AddOwnershipTokensToApiClient(string ownershipToken, int apiClientId if (!currentOwnershipToken.ApiClients.Any(a => a.ApiClientId == apiClientId)) { - var apiClient = context.Clients.FirstOrDefault(a => a.ApiClientId == apiClientId); + var apiClient = context.ApiClients.FirstOrDefault(a => a.ApiClientId == apiClientId); currentOwnershipToken.ApiClients.Add(apiClient); } @@ -139,16 +108,20 @@ public void AddApiClientOwnershipTokens(List ownershipTokens, int apiCli using (var context = _contextFactory.CreateContext()) { var apiClientOwnershipTokenList = new List(); + foreach (var ownershipToken in ownershipTokens) { var ownershiptoken = context.OwnershipTokens.FirstOrDefault(x => x.Description == ownershipToken); - var apiClient = context.Clients.FirstOrDefault(u => u.ApiClientId == apiClientId); - apiClientOwnershipTokenList.Add(new ApiClientOwnershipToken - { - ApiClient = apiClient, - OwnershipToken = ownershiptoken - }); + var apiClient = context.ApiClients.FirstOrDefault(u => u.ApiClientId == apiClientId); + + apiClientOwnershipTokenList.Add( + new ApiClientOwnershipToken + { + ApiClientId = apiClient.ApiClientId, + OwnershipTokenId = ownershiptoken.OwnershipTokenId + }); } + context.ApiClientOwnershipTokens.AddRange(apiClientOwnershipTokenList); context.SaveChanges(); } @@ -160,7 +133,7 @@ public void AddProfilesToApplication(List profiles, int applicationId) { foreach (var _profile in profiles) { - var profile = GetOrCreateProfile(_profile.ProfileName , _profile.ProfileDefinition); + var profile = GetOrCreateProfile(_profile.ProfileName, _profile.ProfileDefinition); var currentProfile = context.Profiles .Include(u => u.Applications) @@ -192,7 +165,7 @@ public IEnumerable GetUsers() { using (var context = _contextFactory.CreateContext()) { - return context.Users.Include(u => u.ApiClients.Select(ac => ac.Application)) + return context.Users.Include(u => u.ApiClients).ThenInclude(ac => ac.Application) .ToList(); } } @@ -202,7 +175,7 @@ public User GetUser(int userId) using (var context = _contextFactory.CreateContext()) { return - context.Users.Include(u => u.ApiClients.Select(ac => ac.Application)) + context.Users.Include(u => u.ApiClients).ThenInclude(ac => ac.Application) .FirstOrDefault(u => u.UserId == userId); } } @@ -212,7 +185,7 @@ public User GetUser(string userName) using (var context = _contextFactory.CreateContext()) { return - context.Users.Include(u => u.ApiClients.Select(ac => ac.Application)) + context.Users.Include(u => u.ApiClients).ThenInclude(a => a.Application) .Include(u => u.Vendor) .FirstOrDefault(x => x.Email == userName); } @@ -223,7 +196,7 @@ public void DeleteUser(User userProfile) using (var context = _contextFactory.CreateContext()) { var user = - context.Users.Include(u => u.ApiClients.Select(ac => ac.Application)) + context.Users.Include(u => u.ApiClients).ThenInclude(ac => ac.Application) .FirstOrDefault(x => x.UserId == userProfile.UserId); if (user == null) @@ -235,7 +208,7 @@ public void DeleteUser(User userProfile) foreach (var client in arraySoThatUnderlyingCollectionCanBeModified) { - context.Clients.Remove(client); + context.ApiClients.Remove(client); } context.Users.Remove(user); @@ -247,11 +220,11 @@ public ApiClient GetClient(string key) { using (var context = _contextFactory.CreateContext()) { - return context.Clients.Include(c => c.Application) - .Include(c => c.Application.Vendor) - .Include(c => c.Application.Vendor.VendorNamespacePrefixes) + return context.ApiClients.Include(c => c.Application) + .ThenInclude(c => c.Vendor) + .ThenInclude(c => c.VendorNamespacePrefixes) .Include(c => c.ApplicationEducationOrganizations) - .Include(c => c.CreatorOwnershipTokenId) + .Include(c => c.CreatorOwnershipToken) .FirstOrDefault(c => c.Key == key); } } @@ -260,9 +233,9 @@ public async Task GetClientAsync(string key) { using (var context = _contextFactory.CreateContext()) { - return await context.Clients.Include(c => c.Application) - .Include(c => c.Application.Vendor) - .Include(c => c.Application.Vendor.VendorNamespacePrefixes) + return await context.ApiClients.Include(c => c.Application) + .ThenInclude(a => a.Vendor) + .ThenInclude(v => v.VendorNamespacePrefixes) .Include(c => c.ApplicationEducationOrganizations) .Include(c => c.CreatorOwnershipTokenId) .FirstOrDefaultAsync(c => c.Key == key); @@ -273,7 +246,7 @@ public ApiClient GetClient(string key, string secret) { using (var context = _contextFactory.CreateContext()) { - return context.Clients.FirstOrDefault(c => c.Key == key && c.Secret == secret); + return context.ApiClients.FirstOrDefault(c => c.Key == key && c.Secret == secret); } } @@ -281,7 +254,7 @@ public ApiClient GetClientByKey(string key) { using (var context = _contextFactory.CreateContext()) { - return context.Clients.FirstOrDefault(c => c.Key == key); + return context.ApiClients.FirstOrDefault(c => c.Key == key); } } @@ -289,7 +262,7 @@ public ApiClient UpdateClient(ApiClient client) { using (var context = _contextFactory.CreateContext()) { - context.Clients.AddOrUpdate(client); + context.ApiClients.Update(client); context.SaveChanges(); return client; } @@ -299,7 +272,7 @@ public void DeleteClient(string key) { using (var context = _contextFactory.CreateContext()) { - var client = context.Clients.Include(x=>x.ClientAccessTokens).First(x => x.Key == key); + var client = context.ApiClients.Include(x => x.ClientAccessTokens).First(x => x.Key == key); var apiClientOdsInstances = context.ApiClientOdsInstances.Include(x => x.ApiClient).Include(x => x.OdsInstance) .Where(x => x.ApiClient.ApiClientId == client.ApiClientId); @@ -315,7 +288,7 @@ public void DeleteClient(string key) context.ApiClientOdsInstances.Remove(apiClientOdsInstance); } - context.Clients.Remove(client); + context.ApiClients.Remove(client); context.SaveChanges(); } @@ -336,7 +309,7 @@ public void AddApiClientToUserWithVendorApplication(int userId, ApiClient client { var user = context.Users .Include(u => u.Vendor) - .Include(v => v.Vendor.Applications) + .ThenInclude(v => v.Applications) .SingleOrDefault(u => u.UserId == userId); if (user == null) @@ -349,7 +322,7 @@ public void AddApiClientToUserWithVendorApplication(int userId, ApiClient client client.Application = user.Vendor.Applications.FirstOrDefault(); } - context.Clients.Add(client); + context.ApiClients.Add(client); context.SaveChanges(); } } @@ -384,19 +357,6 @@ public void SetupKeySecret( } } - private ApiClient CreateApiClient( - IUsersContext context, - int userId, - string name, - SandboxType sandboxType, - string key, - string secret) - { - var attachedUser = context.Users.Find(userId); - - return attachedUser.AddSandboxClient(name, sandboxType, key, secret); - } - public void AddEdOrgIdsToApiClient(int userId, int apiClientId, IList edOrgIds, int applicationId) { using (var context = _contextFactory.CreateContext()) @@ -405,7 +365,7 @@ public void AddEdOrgIdsToApiClient(int userId, int apiClientId, IList edOr .Include(a => a.ApplicationEducationOrganizations) .Single(a => a.ApplicationId == applicationId); - var user = context.Users.FirstOrDefault(u => u.UserId == userId); + var user = context.Users.Include(u => u.ApiClients).FirstOrDefault(u => u.UserId == userId); var client = user?.ApiClients.FirstOrDefault(c => c.ApiClientId == apiClientId); @@ -417,7 +377,7 @@ public void AddEdOrgIdsToApiClient(int userId, int apiClientId, IList edOr client.Application = application; foreach (var applicationEducationOrganization in application.ApplicationEducationOrganizations.Where( - s => edOrgIds.Contains(s.EducationOrganizationId))) + s => edOrgIds.Contains(s.EducationOrganizationId))) { client.ApplicationEducationOrganizations.Add(applicationEducationOrganization); } @@ -426,20 +386,6 @@ public void AddEdOrgIdsToApiClient(int userId, int apiClientId, IList edOr } } - private void AddApplicationEducationOrganizations(IUsersContext context, int applicationId, ApiClient client) - { - var defaultApplication = context.Applications - .Include(a => a.ApplicationEducationOrganizations) - .First(a => a.ApplicationId == applicationId); - - client.Application = defaultApplication; - - foreach (var applicationEducationOrganization in defaultApplication.ApplicationEducationOrganizations) - { - client.ApplicationEducationOrganizations.Add(applicationEducationOrganization); - } - } - public ApiClient SetupDefaultSandboxClient( string name, SandboxType sandboxType, @@ -505,7 +451,8 @@ public void SetDefaultVendorOnUserFromEmailAndName(string userEmail, string user SetDefaultVendorOnUserFromEmailAndName(userEmail, userName, new List { namespacePrefix }); } - public void SetDefaultVendorOnUserFromEmailAndName(string userEmail, string userName, IEnumerable namespacePrefixes) + public void SetDefaultVendorOnUserFromEmailAndName(string userEmail, string userName, + IEnumerable namespacePrefixes) { using (var context = _contextFactory.CreateContext()) { @@ -522,8 +469,8 @@ public void SetDefaultVendorOnUserFromEmailAndName(string userEmail, string user user.Vendor = vendor; } - context.Vendors.AddOrUpdate(vendor); - context.Users.AddOrUpdate(user); + context.Vendors.Update(vendor); + context.Users.Update(user); context.SaveChanges(); } } @@ -547,28 +494,6 @@ public Vendor CreateOrGetVendor(string userEmail, string userName, IEnumerable namespacePrefixes) - { - using (var context = _contextFactory.CreateContext()) - { - var vendor = context.Vendors.FirstOrDefault(v => v.VendorName == vendorName); - - if (vendor != null) - { - return vendor; - } - - var newVendor = Vendor.Create(vendorName, namespacePrefixes); - - context.Vendors.AddOrUpdate(newVendor); - - //TODO: DEA - Move this behavior to happen during client creation. No need to do this in two places. At a minimum, remove the duplicated code. - CreateDefaultApplicationForVendor(newVendor); - - return newVendor; - } - } - public Application CreateApplicationForVendor(int vendorId, string applicationName, string claimSetName) { using (var context = _contextFactory.CreateContext()) @@ -592,14 +517,14 @@ public Application CreateApplicationForVendor(int vendorId, string applicationNa OperationalContextUri = _defaultOperationalContextUri.Value }; - context.Applications.AddOrUpdate(app); + context.Applications.Update(app); context.SaveChanges(); return app; } } - + public OdsInstance CreateOdsInstance(OdsInstance odsInstance) { using (var context = _contextFactory.CreateContext()) @@ -614,8 +539,9 @@ public void AddOdsInstanceToApiClient(int apiClientId, int odsInstanceId) { using (var context = _contextFactory.CreateContext()) { - var apiClient = context.Clients.Single(a => a.ApiClientId == apiClientId); + var apiClient = context.ApiClients.Single(a => a.ApiClientId == apiClientId); var odsInstance = context.OdsInstances.Single(o => o.OdsInstanceId == odsInstanceId); + var apiClientOdsInstance = new ApiClientOdsInstance() { ApiClient = apiClient, @@ -627,6 +553,94 @@ public void AddOdsInstanceToApiClient(int apiClientId, int odsInstanceId) } } + private Profile GetOrCreateProfile(string profileName, string profileDefinition) + { + using (var context = _contextFactory.CreateContext()) + { + var profiles = context.Profiles.FirstOrDefault(s => s.ProfileName == profileName); + + if (profiles == null) + { + context.Profiles.Add( + new Profile + { + ProfileName = profileName, + ProfileDefinition = profileDefinition + }); + + context.SaveChanges(); + } + + return context.Profiles.FirstOrDefault(s => s.ProfileName == profileName); + } + } + + private OwnershipToken GetOrCreateOwnershipToken(string ownershipToken) + { + using (var context = _contextFactory.CreateContext()) + { + var ownershipTokens = context.OwnershipTokens.FirstOrDefault(s => s.Description == ownershipToken); + + if (ownershipTokens == null) + { + context.OwnershipTokens.Add(new OwnershipToken { Description = ownershipToken }); + context.SaveChanges(); + } + + return context.OwnershipTokens.FirstOrDefault(s => s.Description == ownershipToken); + } + } + + private ApiClient CreateApiClient( + IUsersContext context, + int userId, + string name, + SandboxType sandboxType, + string key, + string secret) + { + var attachedUser = context.Users.Find(userId); + + return attachedUser.AddSandboxClient(name, sandboxType, key, secret); + } + + private void AddApplicationEducationOrganizations(IUsersContext context, int applicationId, ApiClient client) + { + var defaultApplication = context.Applications + .Include(a => a.ApplicationEducationOrganizations) + .First(a => a.ApplicationId == applicationId); + + client.Application = defaultApplication; + + foreach (var applicationEducationOrganization in defaultApplication.ApplicationEducationOrganizations) + { + client.ApplicationEducationOrganizations.Add(applicationEducationOrganization); + context.ApplicationEducationOrganizations.Add(applicationEducationOrganization); + } + } + + private Vendor FindOrCreateVendorByDomainName(string vendorName, IEnumerable namespacePrefixes) + { + using (var context = _contextFactory.CreateContext()) + { + var vendor = context.Vendors.FirstOrDefault(v => v.VendorName == vendorName); + + if (vendor != null) + { + return vendor; + } + + var newVendor = Vendor.Create(vendorName, namespacePrefixes); + + context.Vendors.Update(newVendor); + + //TODO: DEA - Move this behavior to happen during client creation. No need to do this in two places. At a minimum, remove the duplicated code. + CreateDefaultApplicationForVendor(newVendor); + + return newVendor; + } + } + private void CreateDefaultApplicationForVendor(Vendor vendor) { using (var context = _contextFactory.CreateContext()) @@ -639,7 +653,7 @@ private void CreateDefaultApplicationForVendor(Vendor vendor) return; } - context.Applications.AddOrUpdate( + context.Applications.Update( new Application { ApplicationName = _defaultAppName.Value, diff --git a/Application/EdFi.Admin.DataAccess/Repositories/IClientAppRepo.cs b/Application/EdFi.Admin.DataAccess/Repositories/IClientAppRepo.cs index 5d055b118e..8502b0f2be 100644 --- a/Application/EdFi.Admin.DataAccess/Repositories/IClientAppRepo.cs +++ b/Application/EdFi.Admin.DataAccess/Repositories/IClientAppRepo.cs @@ -11,7 +11,6 @@ namespace EdFi.Admin.DataAccess.Repositories { public interface IClientAppRepo { - void CreateProfilesWithProfileDefinition(List profiles); void AddProfilesToApplication(List profiles, int applicationId); @@ -42,9 +41,11 @@ public interface IClientAppRepo void AddApiClientToUserWithVendorApplication(int userId, ApiClient client); - ApiClient SetupDefaultSandboxClient(string name, SandboxType sandboxType, string key, string secret, int userId, int applicationId); + ApiClient SetupDefaultSandboxClient(string name, SandboxType sandboxType, string key, string secret, int userId, + int applicationId); - void SetupKeySecret(string name, SandboxType sandboxType, string key, string secret, int userId, int applicationId); + void SetupKeySecret(string name, SandboxType sandboxType, string key, string secret, int userId, + int applicationId); Vendor CreateOrGetVendor(string userEmail, string userName, IEnumerable namespacePrefixes); diff --git a/Application/EdFi.Admin.DataAccess/Security/EdFiAdminApiClientSecretWriter.cs b/Application/EdFi.Admin.DataAccess/Security/EdFiAdminApiClientSecretWriter.cs index b9a15fb986..7f8bbd15df 100644 --- a/Application/EdFi.Admin.DataAccess/Security/EdFiAdminApiClientSecretWriter.cs +++ b/Application/EdFi.Admin.DataAccess/Security/EdFiAdminApiClientSecretWriter.cs @@ -34,7 +34,7 @@ public void SetSecret(string key, ApiClientSecret secret) private ApiClient GetClientByKey(string key) { - var client = _clientAppRepo.GetClientByKey(key); + var client = _clientAppRepo.GetClientByKey(key); if (client == null) { diff --git a/Application/EdFi.Admin.DataAccess/Utils/DatabaseNameBuilder.cs b/Application/EdFi.Admin.DataAccess/Utils/DatabaseNameBuilder.cs index 8450d07488..eb3644525a 100644 --- a/Application/EdFi.Admin.DataAccess/Utils/DatabaseNameBuilder.cs +++ b/Application/EdFi.Admin.DataAccess/Utils/DatabaseNameBuilder.cs @@ -21,7 +21,8 @@ public class DatabaseNameBuilder : IDatabaseNameBuilder private readonly Lazy _databaseNameTemplate; - public DatabaseNameBuilder(IConfigConnectionStringsProvider connectionStringsProvider, IDbConnectionStringBuilderAdapterFactory connectionStringBuilderFactory) + public DatabaseNameBuilder(IConfigConnectionStringsProvider connectionStringsProvider, + IDbConnectionStringBuilderAdapterFactory connectionStringBuilderFactory) { _databaseNameTemplate = new Lazy( () => @@ -65,8 +66,9 @@ public string SampleDatabase public string TemplateSandboxNameForKey(string key) => SandboxPrefix + key; - private string DatabaseName(string databaseName) => _databaseNameTemplate.Value.IsFormatString() - ? string.Format(_databaseNameTemplate.Value, databaseName) - : _databaseNameTemplate.Value; + private string DatabaseName(string databaseName) + => _databaseNameTemplate.Value.IsFormatString() + ? string.Format(_databaseNameTemplate.Value, databaseName) + : _databaseNameTemplate.Value; } } diff --git a/Application/EdFi.Admin.DataAccess/Utils/DefaultApplicationCreator.cs b/Application/EdFi.Admin.DataAccess/Utils/DefaultApplicationCreator.cs index 4795a854a9..52e712df3f 100644 --- a/Application/EdFi.Admin.DataAccess/Utils/DefaultApplicationCreator.cs +++ b/Application/EdFi.Admin.DataAccess/Utils/DefaultApplicationCreator.cs @@ -4,12 +4,11 @@ // See the LICENSE and NOTICES files in the project root for more information. using System.Collections.Generic; -using System.Data.Entity; -using System.Data.Entity.Migrations; using System.Linq; using EdFi.Admin.DataAccess.Contexts; using EdFi.Admin.DataAccess.Models; using EdFi.Common; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; namespace EdFi.Admin.DataAccess.Utils @@ -39,9 +38,9 @@ public Application FindOrCreateUpdatedDefaultSandboxApplication(int vendorId, Sa using (var context = _usersContextFactory.CreateContext()) { var vendor = context.Vendors - .Where(x => x.VendorId == vendorId) - .Include(x => x.Applications.Select>(a => a.ApplicationEducationOrganizations)) - .Single(); + .Where(x => x.VendorId == vendorId) + .Include(x => x.Applications).ThenInclude(x => x.ApplicationEducationOrganizations) + .Single(); var defaultAppName = _configuration.GetSection("DefaultApplicationName").Value ?? "Default Sandbox Application"; var applicationName = defaultAppName + " " + sandboxType; @@ -56,7 +55,8 @@ public void AddEdOrgIdsToApplication(IList edOrgIds, int applicationId) { using (var context = _usersContextFactory.CreateContext()) { - var application = context.Applications.SingleOrDefault(a => a.ApplicationId == applicationId); + var application = context.Applications.Include(a => a.ApiClients) + .SingleOrDefault(a => a.ApplicationId == applicationId); if (application != null) { @@ -66,7 +66,7 @@ public void AddEdOrgIdsToApplication(IList edOrgIds, int applicationId) { var applicationEducationOrganization = application.CreateApplicationEducationOrganization(edOrgId); application.ApplicationEducationOrganizations.Add(applicationEducationOrganization); - context.ApplicationEducationOrganizations.AddOrUpdate(applicationEducationOrganization); + context.ApplicationEducationOrganizations.Add(applicationEducationOrganization); } } @@ -90,4 +90,4 @@ private Application GetApplication(IUsersContext context, Vendor vendor, string return newApplication; } } -} \ No newline at end of file +} diff --git a/Application/EdFi.Admin.DataAccess/Utils/EdFiOdsConnectionStringBuilder.cs b/Application/EdFi.Admin.DataAccess/Utils/EdFiOdsConnectionStringBuilder.cs index 6ac3ce0ff5..676049f911 100644 --- a/Application/EdFi.Admin.DataAccess/Utils/EdFiOdsConnectionStringBuilder.cs +++ b/Application/EdFi.Admin.DataAccess/Utils/EdFiOdsConnectionStringBuilder.cs @@ -3,10 +3,9 @@ // 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.Configuration; -using System.Data.SqlClient; using EdFi.Common.Extensions; +using Microsoft.Data.SqlClient; namespace EdFi.Admin.DataAccess.Utils { diff --git a/Application/EdFi.Admin.DataAccess/Utils/ValidateDatabase.cs b/Application/EdFi.Admin.DataAccess/Utils/ValidateDatabase.cs deleted file mode 100644 index 3e2a04bffc..0000000000 --- a/Application/EdFi.Admin.DataAccess/Utils/ValidateDatabase.cs +++ /dev/null @@ -1,30 +0,0 @@ -// 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; -using System.Configuration; -using System.Data.Entity; -using System.Transactions; -using EdFi.Common; - -namespace EdFi.Admin.DataAccess.Utils -{ - public class ValidateDatabase : IDatabaseInitializer - where TContext : DbContext - { - public void InitializeDatabase(TContext context) - { - Preconditions.ThrowIfNull(context, nameof(context)); - - using (new TransactionScope(TransactionScopeOption.Suppress)) - { - if (!context.Database.Exists()) - { - throw new ConfigurationErrorsException("Unable to open connection to the Admin database."); - } - } - } - } -} diff --git a/Application/EdFi.Common/EdFi.Common.csproj b/Application/EdFi.Common/EdFi.Common.csproj index 200e394e64..b195c1ac48 100644 --- a/Application/EdFi.Common/EdFi.Common.csproj +++ b/Application/EdFi.Common/EdFi.Common.csproj @@ -14,8 +14,8 @@ - + - + diff --git a/Application/EdFi.Ods.Api/EdFi.Ods.Api.csproj b/Application/EdFi.Ods.Api/EdFi.Ods.Api.csproj index d418b791b3..decdec1301 100644 --- a/Application/EdFi.Ods.Api/EdFi.Ods.Api.csproj +++ b/Application/EdFi.Ods.Api/EdFi.Ods.Api.csproj @@ -26,8 +26,8 @@ - - + + @@ -45,6 +45,7 @@ + diff --git a/Application/EdFi.Ods.Api/Security/Profiles/AdminProfileNamesPublisher.cs b/Application/EdFi.Ods.Api/Security/Profiles/AdminProfileNamesPublisher.cs index 8d2bf056bc..1a8e7c04c2 100644 --- a/Application/EdFi.Ods.Api/Security/Profiles/AdminProfileNamesPublisher.cs +++ b/Application/EdFi.Ods.Api/Security/Profiles/AdminProfileNamesPublisher.cs @@ -4,13 +4,14 @@ // See the LICENSE and NOTICES files in the project root for more information. using System; -using System.Data.Entity; using System.Linq; +using System.Threading; using System.Threading.Tasks; using EdFi.Admin.DataAccess.Contexts; using EdFi.Admin.DataAccess.Models; using EdFi.Ods.Common.Metadata.Profiles; using log4net; +using Microsoft.EntityFrameworkCore; namespace EdFi.Ods.Api.Security.Profiles { @@ -47,7 +48,7 @@ public async Task PublishProfilesAsync() { if (_logger.IsDebugEnabled) { - string adminDatabaseName = (usersContext as DbContext)?.Database.Connection.Database; + string adminDatabaseName = (usersContext as DbContext)?.Database.GetDbConnection().Database; _logger.Debug($"No profile names need to be published to the Admin database '{adminDatabaseName}'..."); } @@ -56,7 +57,7 @@ public async Task PublishProfilesAsync() if (_logger.IsDebugEnabled) { - string adminDatabaseName = (usersContext as DbContext)?.Database.Connection.Database; + string adminDatabaseName = (usersContext as DbContext)?.Database.GetDbConnection().Database; _logger.Debug($"Publishing the following Profile names to the Admin database '{adminDatabaseName}': {string.Join("', '", profilesToInsert)}"); } @@ -66,7 +67,7 @@ public async Task PublishProfilesAsync() usersContext.Profiles.Add(new Profile { ProfileName = profileName }); } - await usersContext.SaveChangesAsync(); + await usersContext.SaveChangesAsync(new CancellationToken()); } return true; diff --git a/Application/EdFi.Ods.Api/Startup/OdsStartupBase.cs b/Application/EdFi.Ods.Api/Startup/OdsStartupBase.cs index 071eefe742..fb14617f43 100644 --- a/Application/EdFi.Ods.Api/Startup/OdsStartupBase.cs +++ b/Application/EdFi.Ods.Api/Startup/OdsStartupBase.cs @@ -3,31 +3,41 @@ // 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.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.Loader; +using System.Security.Claims; using Autofac; using Autofac.Core; using Autofac.Extensions.DependencyInjection; -using EdFi.Common.Configuration; using EdFi.Common.InversionOfControl; -using EdFi.Ods.Api.Caching; using EdFi.Ods.Api.Configuration; using EdFi.Ods.Api.Constants; -using EdFi.Ods.Api.ExceptionHandling; using EdFi.Ods.Api.Extensions; using EdFi.Ods.Api.ExternalTasks; using EdFi.Ods.Api.Helpers; using EdFi.Ods.Api.InversionOfControl; +using EdFi.Ods.Api.Jobs.Extensions; using EdFi.Ods.Api.MediaTypeFormatters; using EdFi.Ods.Api.Middleware; +using EdFi.Ods.Common; using EdFi.Ods.Common.Caching; using EdFi.Ods.Common.Configuration; +using EdFi.Ods.Common.Configuration.Sections; using EdFi.Ods.Common.Constants; using EdFi.Ods.Common.Container; +using EdFi.Ods.Common.Context; using EdFi.Ods.Common.Conventions; +using EdFi.Ods.Common.Database; using EdFi.Ods.Common.Dependencies; +using EdFi.Ods.Common.Descriptors; using EdFi.Ods.Common.Infrastructure.Configuration; using EdFi.Ods.Common.Infrastructure.Extensibility; using EdFi.Ods.Common.Models; using EdFi.Ods.Common.Models.Resource; +using EdFi.Ods.Common.Profiles; using EdFi.Ods.Common.Security.Claims; using log4net; using Microsoft.AspNetCore.Authentication; @@ -35,7 +45,6 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.HttpOverrides; -using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ApplicationParts; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Routing; @@ -43,22 +52,8 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Data.Entity; -using System.IO; -using System.Linq; -using System.Runtime.Loader; -using System.Security.Claims; -using EdFi.Admin.DataAccess.DbConfigurations; -using EdFi.Ods.Api.Jobs.Extensions; -using EdFi.Ods.Common; -using EdFi.Ods.Common.Configuration.Sections; -using EdFi.Ods.Common.Context; -using EdFi.Ods.Common.Database; -using EdFi.Ods.Common.Descriptors; -using EdFi.Ods.Common.Profiles; using Microsoft.Extensions.Options; +using Environment = NHibernate.Cfg.Environment; namespace EdFi.Ods.Api.Startup { @@ -180,7 +175,6 @@ public void ConfigureServices(IServiceCollection services) services.AddApplicationInsightsTelemetry( options => { options.ApplicationVersion = ApiVersionConstants.Version; }); - services.AddAuthorization( options => { @@ -372,9 +366,7 @@ void SetStaticResolvers() .GetResourceModel()); EntityExtensionsFactory.Instance = Container.Resolve(); - - DbConfiguration.SetConfiguration(new DatabaseEngineDbConfiguration(Container.Resolve())); - + // Set NHibernate to use Autofac to resolve its dependencies NHibernate.Cfg.Environment.ObjectsFactory = new NHibernateAutofacObjectsFactory(Container); } diff --git a/Application/EdFi.Ods.Common/EdFi.Ods.Common.csproj b/Application/EdFi.Ods.Common/EdFi.Ods.Common.csproj index 9b7b6f4579..2ea3c6af79 100644 --- a/Application/EdFi.Ods.Common/EdFi.Ods.Common.csproj +++ b/Application/EdFi.Ods.Common/EdFi.Ods.Common.csproj @@ -36,12 +36,12 @@ - + - + diff --git a/Application/EdFi.Ods.Sandbox/EdFi.Ods.Sandbox.csproj b/Application/EdFi.Ods.Sandbox/EdFi.Ods.Sandbox.csproj index 2d74684837..d3a432108d 100644 --- a/Application/EdFi.Ods.Sandbox/EdFi.Ods.Sandbox.csproj +++ b/Application/EdFi.Ods.Sandbox/EdFi.Ods.Sandbox.csproj @@ -20,17 +20,16 @@ - + - - + - + diff --git a/Application/EdFi.Ods.Standard/Standard/5.0.0/Artifacts/Metadata/DatabaseViews.generated.json b/Application/EdFi.Ods.Standard/Standard/5.0.0/Artifacts/Metadata/DatabaseViews.generated.json index dda1ca5cfb..d9232cddd2 100644 --- a/Application/EdFi.Ods.Standard/Standard/5.0.0/Artifacts/Metadata/DatabaseViews.generated.json +++ b/Application/EdFi.Ods.Standard/Standard/5.0.0/Artifacts/Metadata/DatabaseViews.generated.json @@ -1,278 +1,278 @@ -[ - { - "SchemaOwner": "auth", - "Name": "EducationOrganizationIdToContactUSI", - "Columns": [ - { - "Name": "SourceEducationOrganizationId", - "DbDataType": "bigint", - "IsPrimaryKey": false, - "Length": null, - "Precision": 19, - "Scale": 0, - "Nullable": false - }, - { - "Name": "ContactUSI", - "DbDataType": "int", - "IsPrimaryKey": false, - "Length": null, - "Precision": 10, - "Scale": 0, - "Nullable": false - }, - { - "Name": "Ignored", - "DbDataType": "bigint", - "IsPrimaryKey": false, - "Length": null, - "Precision": 19, - "Scale": 0, - "Nullable": true - } - ] - }, - { - "SchemaOwner": "auth", - "Name": "EducationOrganizationIdToContactUSIIncludingDeletes", - "Columns": [ - { - "Name": "SourceEducationOrganizationId", - "DbDataType": "bigint", - "IsPrimaryKey": false, - "Length": null, - "Precision": 19, - "Scale": 0, - "Nullable": false - }, - { - "Name": "ContactUSI", - "DbDataType": "int", - "IsPrimaryKey": false, - "Length": null, - "Precision": 10, - "Scale": 0, - "Nullable": false - } - ] - }, - { - "SchemaOwner": "auth", - "Name": "EducationOrganizationIdToStaffUSI", - "Columns": [ - { - "Name": "SourceEducationOrganizationId", - "DbDataType": "bigint", - "IsPrimaryKey": false, - "Length": null, - "Precision": 19, - "Scale": 0, - "Nullable": false - }, - { - "Name": "StaffUSI", - "DbDataType": "int", - "IsPrimaryKey": false, - "Length": null, - "Precision": 10, - "Scale": 0, - "Nullable": false - } - ] - }, - { - "SchemaOwner": "auth", - "Name": "EducationOrganizationIdToStaffUSIIncludingDeletes", - "Columns": [ - { - "Name": "SourceEducationOrganizationId", - "DbDataType": "bigint", - "IsPrimaryKey": false, - "Length": null, - "Precision": 19, - "Scale": 0, - "Nullable": false - }, - { - "Name": "StaffUSI", - "DbDataType": "int", - "IsPrimaryKey": false, - "Length": null, - "Precision": 10, - "Scale": 0, - "Nullable": false - } - ] - }, - { - "SchemaOwner": "auth", - "Name": "EducationOrganizationIdToStudentUSI", - "Columns": [ - { - "Name": "SourceEducationOrganizationId", - "DbDataType": "bigint", - "IsPrimaryKey": false, - "Length": null, - "Precision": 19, - "Scale": 0, - "Nullable": false - }, - { - "Name": "StudentUSI", - "DbDataType": "int", - "IsPrimaryKey": false, - "Length": null, - "Precision": 10, - "Scale": 0, - "Nullable": false - }, - { - "Name": "Ignored", - "DbDataType": "bigint", - "IsPrimaryKey": false, - "Length": null, - "Precision": 19, - "Scale": 0, - "Nullable": true - } - ] - }, - { - "SchemaOwner": "auth", - "Name": "EducationOrganizationIdToStudentUSIIncludingDeletes", - "Columns": [ - { - "Name": "SourceEducationOrganizationId", - "DbDataType": "bigint", - "IsPrimaryKey": false, - "Length": null, - "Precision": 19, - "Scale": 0, - "Nullable": false - }, - { - "Name": "StudentUSI", - "DbDataType": "int", - "IsPrimaryKey": false, - "Length": null, - "Precision": 10, - "Scale": 0, - "Nullable": false - } - ] - }, - { - "SchemaOwner": "auth", - "Name": "EducationOrganizationIdToStudentUSIThroughDeletedResponsibility", - "Columns": [ - { - "Name": "SourceEducationOrganizationId", - "DbDataType": "bigint", - "IsPrimaryKey": false, - "Length": null, - "Precision": 19, - "Scale": 0, - "Nullable": false - }, - { - "Name": "StudentUSI", - "DbDataType": "int", - "IsPrimaryKey": false, - "Length": null, - "Precision": 10, - "Scale": 0, - "Nullable": false - } - ] - }, - { - "SchemaOwner": "auth", - "Name": "EducationOrganizationIdToStudentUSIThroughResponsibility", - "Columns": [ - { - "Name": "SourceEducationOrganizationId", - "DbDataType": "bigint", - "IsPrimaryKey": false, - "Length": null, - "Precision": 19, - "Scale": 0, - "Nullable": false - }, - { - "Name": "StudentUSI", - "DbDataType": "int", - "IsPrimaryKey": false, - "Length": null, - "Precision": 10, - "Scale": 0, - "Nullable": false - } - ] - }, - { - "SchemaOwner": "interop", - "Name": "OperationalContextSupport", - "Columns": [ - { - "Name": "SourceDescriptorUri", - "DbDataType": "nvarchar", - "IsPrimaryKey": false, - "Length": 306, - "Precision": null, - "Scale": null, - "Nullable": false - }, - { - "Name": "TargetOperationalContextUri", - "DbDataType": "nvarchar", - "IsPrimaryKey": false, - "Length": 255, - "Precision": null, - "Scale": null, - "Nullable": false - }, - { - "Name": "TargetDescriptorUri", - "DbDataType": "nvarchar", - "IsPrimaryKey": false, - "Length": 306, - "Precision": null, - "Scale": null, - "Nullable": false - }, - { - "Name": "IsGeneralized", - "DbDataType": "int", - "IsPrimaryKey": false, - "Length": null, - "Precision": 10, - "Scale": 0, - "Nullable": false - } - ] - }, - { - "SchemaOwner": "auth", - "Name": "EducationOrganizationIdToEducationOrganizationId", - "Columns": [ - { - "Name": "SourceEducationOrganizationId", - "DbDataType": "bigint", - "IsPrimaryKey": true, - "Length": null, - "Precision": 19, - "Scale": 0, - "Nullable": false - }, - { - "Name": "TargetEducationOrganizationId", - "DbDataType": "bigint", - "IsPrimaryKey": true, - "Length": null, - "Precision": 19, - "Scale": 0, - "Nullable": false - } - ] - } +[ + { + "SchemaOwner": "auth", + "Name": "EducationOrganizationIdToContactUSI", + "Columns": [ + { + "Name": "SourceEducationOrganizationId", + "DbDataType": "bigint", + "IsPrimaryKey": false, + "Length": null, + "Precision": 19, + "Scale": 0, + "Nullable": false + }, + { + "Name": "ContactUSI", + "DbDataType": "int", + "IsPrimaryKey": false, + "Length": null, + "Precision": 10, + "Scale": 0, + "Nullable": false + }, + { + "Name": "Ignored", + "DbDataType": "bigint", + "IsPrimaryKey": false, + "Length": null, + "Precision": 19, + "Scale": 0, + "Nullable": true + } + ] + }, + { + "SchemaOwner": "auth", + "Name": "EducationOrganizationIdToContactUSIIncludingDeletes", + "Columns": [ + { + "Name": "SourceEducationOrganizationId", + "DbDataType": "bigint", + "IsPrimaryKey": false, + "Length": null, + "Precision": 19, + "Scale": 0, + "Nullable": false + }, + { + "Name": "ContactUSI", + "DbDataType": "int", + "IsPrimaryKey": false, + "Length": null, + "Precision": 10, + "Scale": 0, + "Nullable": false + } + ] + }, + { + "SchemaOwner": "auth", + "Name": "EducationOrganizationIdToStaffUSI", + "Columns": [ + { + "Name": "SourceEducationOrganizationId", + "DbDataType": "bigint", + "IsPrimaryKey": false, + "Length": null, + "Precision": 19, + "Scale": 0, + "Nullable": false + }, + { + "Name": "StaffUSI", + "DbDataType": "int", + "IsPrimaryKey": false, + "Length": null, + "Precision": 10, + "Scale": 0, + "Nullable": false + } + ] + }, + { + "SchemaOwner": "auth", + "Name": "EducationOrganizationIdToStaffUSIIncludingDeletes", + "Columns": [ + { + "Name": "SourceEducationOrganizationId", + "DbDataType": "bigint", + "IsPrimaryKey": false, + "Length": null, + "Precision": 19, + "Scale": 0, + "Nullable": false + }, + { + "Name": "StaffUSI", + "DbDataType": "int", + "IsPrimaryKey": false, + "Length": null, + "Precision": 10, + "Scale": 0, + "Nullable": false + } + ] + }, + { + "SchemaOwner": "auth", + "Name": "EducationOrganizationIdToStudentUSI", + "Columns": [ + { + "Name": "SourceEducationOrganizationId", + "DbDataType": "bigint", + "IsPrimaryKey": false, + "Length": null, + "Precision": 19, + "Scale": 0, + "Nullable": false + }, + { + "Name": "StudentUSI", + "DbDataType": "int", + "IsPrimaryKey": false, + "Length": null, + "Precision": 10, + "Scale": 0, + "Nullable": false + }, + { + "Name": "Ignored", + "DbDataType": "bigint", + "IsPrimaryKey": false, + "Length": null, + "Precision": 19, + "Scale": 0, + "Nullable": true + } + ] + }, + { + "SchemaOwner": "auth", + "Name": "EducationOrganizationIdToStudentUSIIncludingDeletes", + "Columns": [ + { + "Name": "SourceEducationOrganizationId", + "DbDataType": "bigint", + "IsPrimaryKey": false, + "Length": null, + "Precision": 19, + "Scale": 0, + "Nullable": false + }, + { + "Name": "StudentUSI", + "DbDataType": "int", + "IsPrimaryKey": false, + "Length": null, + "Precision": 10, + "Scale": 0, + "Nullable": false + } + ] + }, + { + "SchemaOwner": "auth", + "Name": "EducationOrganizationIdToStudentUSIThroughDeletedResponsibility", + "Columns": [ + { + "Name": "SourceEducationOrganizationId", + "DbDataType": "bigint", + "IsPrimaryKey": false, + "Length": null, + "Precision": 19, + "Scale": 0, + "Nullable": false + }, + { + "Name": "StudentUSI", + "DbDataType": "int", + "IsPrimaryKey": false, + "Length": null, + "Precision": 10, + "Scale": 0, + "Nullable": false + } + ] + }, + { + "SchemaOwner": "auth", + "Name": "EducationOrganizationIdToStudentUSIThroughResponsibility", + "Columns": [ + { + "Name": "SourceEducationOrganizationId", + "DbDataType": "bigint", + "IsPrimaryKey": false, + "Length": null, + "Precision": 19, + "Scale": 0, + "Nullable": false + }, + { + "Name": "StudentUSI", + "DbDataType": "int", + "IsPrimaryKey": false, + "Length": null, + "Precision": 10, + "Scale": 0, + "Nullable": false + } + ] + }, + { + "SchemaOwner": "interop", + "Name": "OperationalContextSupport", + "Columns": [ + { + "Name": "SourceDescriptorUri", + "DbDataType": "nvarchar", + "IsPrimaryKey": false, + "Length": 306, + "Precision": null, + "Scale": null, + "Nullable": false + }, + { + "Name": "TargetOperationalContextUri", + "DbDataType": "nvarchar", + "IsPrimaryKey": false, + "Length": 255, + "Precision": null, + "Scale": null, + "Nullable": false + }, + { + "Name": "TargetDescriptorUri", + "DbDataType": "nvarchar", + "IsPrimaryKey": false, + "Length": 306, + "Precision": null, + "Scale": null, + "Nullable": false + }, + { + "Name": "IsGeneralized", + "DbDataType": "int", + "IsPrimaryKey": false, + "Length": null, + "Precision": 10, + "Scale": 0, + "Nullable": false + } + ] + }, + { + "SchemaOwner": "auth", + "Name": "EducationOrganizationIdToEducationOrganizationId", + "Columns": [ + { + "Name": "SourceEducationOrganizationId", + "DbDataType": "bigint", + "IsPrimaryKey": true, + "Length": null, + "Precision": 19, + "Scale": 0, + "Nullable": false + }, + { + "Name": "TargetEducationOrganizationId", + "DbDataType": "bigint", + "IsPrimaryKey": true, + "Length": null, + "Precision": 19, + "Scale": 0, + "Nullable": false + } + ] + } ] diff --git a/Application/EdFi.Ods.Tests/EdFi.Ods.Sandbox/Repositories/ClientAppRepoTests.cs b/Application/EdFi.Ods.Tests/EdFi.Ods.Sandbox/Repositories/ClientAppRepoTests.cs index 7443ea49ee..62a67fae61 100644 --- a/Application/EdFi.Ods.Tests/EdFi.Ods.Sandbox/Repositories/ClientAppRepoTests.cs +++ b/Application/EdFi.Ods.Tests/EdFi.Ods.Sandbox/Repositories/ClientAppRepoTests.cs @@ -6,8 +6,9 @@ using System; using EdFi.Admin.DataAccess.Contexts; using EdFi.Admin.DataAccess.Models; +using EdFi.Admin.DataAccess.Providers; using EdFi.Admin.DataAccess.Repositories; -using EdFi.TestFixture; +using EdFi.Common.Configuration; using FakeItEasy; using NUnit.Framework; using Microsoft.Extensions.Configuration; @@ -23,19 +24,30 @@ public class When_calling_the_clientAppRepo { private ClientAppRepo _clientAppRepo; private ApiClient _testClient; + private DatabaseEngine _databaseEngine; [OneTimeSetUp] public void Setup() { - var configValueProviderStub = A.Fake(); - var usersContext = A.Fake(); + var configuration = new ConfigurationBuilder() + .SetBasePath(TestContext.CurrentContext.TestDirectory) + .AddJsonFile("appsettings.json", false) + .AddJsonFile("appsettings.Development.json", true) + .AddEnvironmentVariables() + .Build(); + var engine = configuration.GetSection("ApiSettings").GetValue("Engine"); + + _databaseEngine = DatabaseEngine.TryParseEngine(engine); - var usersContextFactory = A.Fake(); - A.CallTo(() => usersContextFactory.CreateContext()) - .Returns(usersContext); + var connectionStringProvider = A.Fake(); + + A.CallTo(() => connectionStringProvider.GetConnectionString()).Returns( + configuration.GetConnectionString("EdFi_Admin")); - _clientAppRepo = new ClientAppRepo(usersContextFactory, configValueProviderStub); + var usersContextFactory = new UsersContextFactory(connectionStringProvider, _databaseEngine); + + _clientAppRepo = new ClientAppRepo(usersContextFactory, configuration); _testClient = new ApiClient(true) { @@ -43,10 +55,7 @@ public void Setup() .ToString("N") }; - var dbSet = new TestDbSet {_testClient}; - - A.CallTo(() => usersContext.Clients) - .Returns(dbSet); + _clientAppRepo.UpdateClient(_testClient); } [Test] diff --git a/Application/EdFi.Ods.Tests/EdFi.Ods.Tests.csproj b/Application/EdFi.Ods.Tests/EdFi.Ods.Tests.csproj index f328cf6250..89efab161c 100644 --- a/Application/EdFi.Ods.Tests/EdFi.Ods.Tests.csproj +++ b/Application/EdFi.Ods.Tests/EdFi.Ods.Tests.csproj @@ -27,7 +27,7 @@ - + @@ -62,6 +62,9 @@ Always + + Always + diff --git a/Application/EdFi.Security.DataAccess/EdFi.Security.DataAccess.csproj b/Application/EdFi.Security.DataAccess/EdFi.Security.DataAccess.csproj index 3c294f9cb9..8428b9a3de 100644 --- a/Application/EdFi.Security.DataAccess/EdFi.Security.DataAccess.csproj +++ b/Application/EdFi.Security.DataAccess/EdFi.Security.DataAccess.csproj @@ -27,10 +27,10 @@ - - - - + + + + diff --git a/tests/EdFi.Admin.DataAccess.IntegrationTests/Contexts/PostgreSQLUserContextFactoryTests.cs b/tests/EdFi.Admin.DataAccess.IntegrationTests/Contexts/PostgreSQLUserContextFactoryTests.cs index 0635232c5a..dd75c8c8f2 100644 --- a/tests/EdFi.Admin.DataAccess.IntegrationTests/Contexts/PostgreSQLUserContextFactoryTests.cs +++ b/tests/EdFi.Admin.DataAccess.IntegrationTests/Contexts/PostgreSQLUserContextFactoryTests.cs @@ -3,17 +3,14 @@ // 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.Linq; using EdFi.Admin.DataAccess.Contexts; using EdFi.Admin.DataAccess.Models; using EdFi.Admin.DataAccess.Providers; using EdFi.Common.Configuration; -using EdFi.Ods.Api.Configuration; using FakeItEasy; using NUnit.Framework; using Shouldly; -using System.Data.Entity; -using System.Linq; -using EdFi.Admin.DataAccess.DbConfigurations; namespace EdFi.Ods.Admin.DataAccess.IntegrationTests.Contexts { @@ -26,7 +23,6 @@ public void Given_configured_for_Postgres_then_create_PostgresUsersContext_make_ var connectionStringsProvider = A.Fake(); A.CallTo(() => connectionStringsProvider.GetConnectionString()).Returns("Host=localhost; Port=5432; Username=postgres; Database=EdFi_Admin_Test; Application Name=EdFi.Ods.WebApi;"); - DbConfiguration.SetConfiguration(new DatabaseEngineDbConfiguration(DatabaseEngine.Postgres)); var context = new UsersContextFactory(connectionStringsProvider, DatabaseEngine.Postgres) .CreateContext(); diff --git a/tests/EdFi.Admin.DataAccess.IntegrationTests/Contexts/SqlServerUserContextFactoryTests.cs b/tests/EdFi.Admin.DataAccess.IntegrationTests/Contexts/SqlServerUserContextFactoryTests.cs index e5e7bc2a85..c63dd6b744 100644 --- a/tests/EdFi.Admin.DataAccess.IntegrationTests/Contexts/SqlServerUserContextFactoryTests.cs +++ b/tests/EdFi.Admin.DataAccess.IntegrationTests/Contexts/SqlServerUserContextFactoryTests.cs @@ -3,6 +3,7 @@ // 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.Linq; using EdFi.Admin.DataAccess.Contexts; using EdFi.Admin.DataAccess.Models; using EdFi.Admin.DataAccess.Providers; @@ -10,9 +11,6 @@ using FakeItEasy; using NUnit.Framework; using Shouldly; -using System.Data.Entity; -using System.Linq; -using EdFi.Admin.DataAccess.DbConfigurations; namespace EdFi.Ods.Admin.DataAccess.IntegrationTests.Contexts { @@ -25,7 +23,6 @@ public void Given_configured_for_SqlServer_then_create_SqlServerUsersContext_mak var connectionStringsProvider = A.Fake(); A.CallTo(() => connectionStringsProvider.GetConnectionString()).Returns("Server=.;Database=EdFi_Admin_Test;Trusted_Connection=True;"); - DbConfiguration.SetConfiguration(new DatabaseEngineDbConfiguration(DatabaseEngine.SqlServer)); var context = new UsersContextFactory(connectionStringsProvider, DatabaseEngine.SqlServer) .CreateContext(); diff --git a/tests/EdFi.Admin.DataAccess.IntegrationTests/Models/UserContextMappingTests.cs b/tests/EdFi.Admin.DataAccess.IntegrationTests/Models/UserContextMappingTests.cs index 255fba83d4..d024c97e04 100644 --- a/tests/EdFi.Admin.DataAccess.IntegrationTests/Models/UserContextMappingTests.cs +++ b/tests/EdFi.Admin.DataAccess.IntegrationTests/Models/UserContextMappingTests.cs @@ -3,15 +3,14 @@ // 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.Linq; using EdFi.Admin.DataAccess.Models; using EdFi.TestFixture; +using Microsoft.EntityFrameworkCore; using NCrunch.Framework; using NUnit.Framework; using Shouldly; -using System; -using System.Data.Entity; -using System.Data.Entity.Migrations; -using System.Linq; using Test.Common; namespace EdFi.Ods.Admin.DataAccess.IntegrationTests.Models @@ -76,11 +75,11 @@ public void Should_persist_the_lea_mapping_without_explicitly_adding_that_mappin client.ApplicationEducationOrganizations.Add(lea); //Act - context.Clients.Add(client); + context.ApiClients.Add(client); context.SaveChangesForTest(); //Assert - var clientFromDb = context.Clients.Where(x => x.Name == clientName) + var clientFromDb = context.ApiClients.Where(x => x.Name == clientName) .Include(x => x.ApplicationEducationOrganizations) .Single(); @@ -220,7 +219,7 @@ public void Should_create_lea_association() .ElementAt(0) .OperationalContextUri = "uri://ed-fi-api-host.org"; - context.ApplicationEducationOrganizations.AddOrUpdate(educationOrganizationAssociation); + context.ApplicationEducationOrganizations.Update(educationOrganizationAssociation); context.Vendors.Add(vendor); context.SaveChangesForTest(); diff --git a/tests/EdFi.Admin.DataAccess.IntegrationTests/Models/UserContextTestBase.cs b/tests/EdFi.Admin.DataAccess.IntegrationTests/Models/UserContextTestBase.cs index c916f88024..c668c971b3 100644 --- a/tests/EdFi.Admin.DataAccess.IntegrationTests/Models/UserContextTestBase.cs +++ b/tests/EdFi.Admin.DataAccess.IntegrationTests/Models/UserContextTestBase.cs @@ -3,16 +3,14 @@ // 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.Transactions; using EdFi.Admin.DataAccess.Contexts; using EdFi.Admin.DataAccess.Providers; using EdFi.Common.Configuration; using EdFi.TestFixture; using Microsoft.Extensions.Configuration; using NUnit.Framework; -using System; -using System.Data.Entity; -using System.Transactions; -using EdFi.Admin.DataAccess.DbConfigurations; namespace EdFi.Ods.Admin.DataAccess.IntegrationTests.Models { @@ -39,8 +37,6 @@ public void OneTimeSetUp() TestDatabaseEngine = DatabaseEngine.TryParseEngine(engine); var connectionStringProvider = new AdminDatabaseConnectionStringProvider(new ConfigConnectionStringsProvider(config)); - - DbConfiguration.SetConfiguration(new DatabaseEngineDbConfiguration(TestDatabaseEngine)); var userContextFactory = new UsersContextFactory(connectionStringProvider, TestDatabaseEngine); _userContext = userContextFactory.CreateContext() as UsersContext; } diff --git a/tests/EdFi.Admin.DataAccess.IntegrationTests/Repositories/AccessTokenClientRepoTests.cs b/tests/EdFi.Admin.DataAccess.IntegrationTests/Repositories/AccessTokenClientRepoTests.cs index f4978424cb..be2c55c689 100644 --- a/tests/EdFi.Admin.DataAccess.IntegrationTests/Repositories/AccessTokenClientRepoTests.cs +++ b/tests/EdFi.Admin.DataAccess.IntegrationTests/Repositories/AccessTokenClientRepoTests.cs @@ -15,12 +15,10 @@ using System; using System.Collections.Generic; using System.Data.Common; -using System.Data.Entity; -using System.Data.SqlClient; using System.Linq; using System.Transactions; -using EdFi.Admin.DataAccess.DbConfigurations; using EdFi.Ods.Api.Security.Authentication; +using Microsoft.Data.SqlClient; using Npgsql; // ReSharper disable InconsistentNaming @@ -63,10 +61,9 @@ protected override void Arrange() _databaseEngine = DatabaseEngine.TryParseEngine(engine); _connectionStringProvider = new AdminDatabaseConnectionStringProvider(new ConfigConnectionStringsProvider(config)); - DbConfiguration.SetConfiguration(new DatabaseEngineDbConfiguration(_databaseEngine)); var userContextFactory = new UsersContextFactory(_connectionStringProvider, _databaseEngine); TestFixtureContext = userContextFactory.CreateContext(); - + if (_databaseEngine == DatabaseEngine.Postgres) { ExpiredAccessTokenDeleter = new ExpiredAccessTokenDeleter(NpgsqlFactory.Instance, _connectionStringProvider); @@ -94,9 +91,9 @@ public void OneTimeTearDown() _transaction?.Dispose(); } - protected ApiClient LoadAnApiClient(Application application, int apiClientId) + protected ApiClient LoadAnApiClient(Application application) { - var a = TestFixtureContext.Clients.Add( + var a = TestFixtureContext.ApiClients.Add( new ApiClient { Key = "key", @@ -106,12 +103,12 @@ protected ApiClient LoadAnApiClient(Application application, int apiClientId) UseSandbox = true, SandboxType = SandboxType.Minimal, SecretIsHashed = false, - Application = application, - ApiClientId = apiClientId + Application = application }); - + TestFixtureContext.SaveChanges(); - return a; + + return a.Entity; } protected ClientAccessToken LoadAnAccessToken(ApiClient client, DateTime expiration) @@ -125,14 +122,14 @@ protected ClientAccessToken LoadAnAccessToken(ApiClient client, DateTime expirat TestFixtureContext.SaveChanges(); - return a; + return a.Entity; } protected Vendor LoadAVendor() { var a = TestFixtureContext.Vendors.Add(new Vendor()); TestFixtureContext.SaveChanges(); - return a; + return a.Entity; } protected void LoadAVendorNamespacePrefix(Vendor vendor, string namespacePrefix) @@ -159,7 +156,7 @@ protected Application LoadAnApplication(Vendor vendor, string claimSetName) TestFixtureContext.SaveChanges(); - return a; + return a.Entity; } protected ApplicationEducationOrganization LoadAnApplicationEducationOrganization(Application application, @@ -169,12 +166,12 @@ protected ApplicationEducationOrganization LoadAnApplicationEducationOrganizatio new ApplicationEducationOrganization { Application = application, - Clients = new[] { client }, + ApiClients = new[] { client }, EducationOrganizationId = edOrgId }); TestFixtureContext.SaveChanges(); - return a; + return a.Entity; } protected void LoadAProfile(Application application, string profileName) @@ -205,10 +202,10 @@ protected override void Act() protected override void Arrange() { base.Arrange(); - + var vendor = LoadAVendor(); var application = LoadAnApplication(vendor, "whatever"); - var apiClient = LoadAnApiClient(application,1); + var apiClient = LoadAnApiClient(application); _accessToken = LoadAnAccessToken(apiClient, DateTime.UtcNow.AddSeconds(-10)); } @@ -227,7 +224,7 @@ public class Given_an_unexpired_token : AccessTokenClientRepoTests { protected ClientAccessToken AccessToken; protected ApiClient Client; - + [TestFixture] public class When_deleting_access_tokens : Given_an_unexpired_token { @@ -235,7 +232,7 @@ protected override void Arrange() { base.Arrange(); - Client = LoadAnApiClient(null,0); + Client = LoadAnApiClient(null); AccessToken = LoadAnAccessToken(Client, DateTime.UtcNow.AddSeconds(100)); } @@ -265,7 +262,6 @@ public class And_client_has_all_optional_data : Given_an_unexpired_token protected const int edOrgId2 = 34; protected const string profileName1 = "three"; protected const string profileName2 = "four"; - protected const int apiClientId = 5; protected override void Arrange() { @@ -277,7 +273,7 @@ protected override void Arrange() var application = LoadAnApplication(vendor, claimSetName); - Client = LoadAnApiClient(application, apiClientId); + Client = LoadAnApiClient(application); LoadAnApplicationEducationOrganization(application, Client, edOrgId1); LoadAnApplicationEducationOrganization(application, Client, edOrgId2); @@ -384,7 +380,7 @@ protected override void Arrange() base.Arrange(); var application = LoadAnApplication(null, "Sandbox"); - Client = LoadAnApiClient(application,5); + Client = LoadAnApiClient(application); AccessToken = LoadAnAccessToken(Client, DateTime.UtcNow.AddSeconds(100)); } diff --git a/tests/EdFi.Admin.DataAccess.UnitTests/Contexts/UserContextFactoryTests.cs b/tests/EdFi.Admin.DataAccess.UnitTests/Contexts/UserContextFactoryTests.cs index 105c4a6461..3f59ee214b 100644 --- a/tests/EdFi.Admin.DataAccess.UnitTests/Contexts/UserContextFactoryTests.cs +++ b/tests/EdFi.Admin.DataAccess.UnitTests/Contexts/UserContextFactoryTests.cs @@ -4,14 +4,12 @@ // See the LICENSE and NOTICES files in the project root for more information. using System; -using FakeItEasy; using EdFi.Admin.DataAccess.Contexts; using EdFi.Admin.DataAccess.Providers; using EdFi.Common.Configuration; +using FakeItEasy; using NUnit.Framework; using Shouldly; -using EdFi.Admin.DataAccess.DbConfigurations; -using System.Data.Entity; namespace EdFi.Admin.DataAccess.UnitTests.Contexts { @@ -26,7 +24,6 @@ public void Given_configured_for_SqlServer_then_create_SqlServerUsersContext() var connectionStringsProvider = A.Fake(); A.CallTo(() => connectionStringsProvider.GetConnectionString()).Returns("Server=.;Database=EdFi_Admin_Test;Trusted_Connection=true;"); - DbConfiguration.SetConfiguration(new DatabaseEngineDbConfiguration(DatabaseEngine.Postgres)); new UsersContextFactory(connectionStringsProvider, DatabaseEngine.SqlServer) .CreateContext() .ShouldBeOfType() @@ -39,7 +36,6 @@ public void Given_configured_for_Postgres_then_create_PostgresUsersContext() var connectionStringsProvider = A.Fake(); A.CallTo(() => connectionStringsProvider.GetConnectionString()).Returns("Host=localhost; Port=5432; Username=postgres; Database=EdFi_Admin_Test; Application Name=EdFi.Ods.WebApi;"); - DbConfiguration.SetConfiguration(new DatabaseEngineDbConfiguration(DatabaseEngine.Postgres)); new UsersContextFactory(connectionStringsProvider, DatabaseEngine.Postgres) .CreateContext() .ShouldBeOfType() diff --git a/tests/EdFi.Ods.Features.UnitTests/Profiles/ProfileMetadataDatabaseProviderTests.cs b/tests/EdFi.Ods.Features.UnitTests/Profiles/ProfileMetadataDatabaseProviderTests.cs index a096c1cb80..aaea57c97d 100644 --- a/tests/EdFi.Ods.Features.UnitTests/Profiles/ProfileMetadataDatabaseProviderTests.cs +++ b/tests/EdFi.Ods.Features.UnitTests/Profiles/ProfileMetadataDatabaseProviderTests.cs @@ -3,9 +3,7 @@ // 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.Collections.Generic; -using System.Data.Entity; -using System.Linq; +using System.Collections; using System.Xml.Linq; using EdFi.Admin.DataAccess.Contexts; using EdFi.Admin.DataAccess.Models; @@ -13,6 +11,7 @@ using EdFi.Ods.Features.Profiles; using EdFi.TestFixture; using FakeItEasy; +using Microsoft.EntityFrameworkCore; using NUnit.Framework; using Shouldly; @@ -50,11 +49,11 @@ protected override void Arrange() var userContext = Stub(); - var fakeDbSet = A.Fake>(options => options.Implements(typeof(IQueryable))); - A.CallTo(() => fakeDbSet.Provider).Returns(profiles.Provider); - A.CallTo(() => fakeDbSet.Expression).Returns(profiles.Expression); - A.CallTo(() => fakeDbSet.ElementType).Returns(profiles.ElementType); - A.CallTo(() => fakeDbSet.GetEnumerator()).Returns(profiles.GetEnumerator()); + var fakeDbSet = A.Fake>(options => options.Implements(typeof(IQueryable))); + A.CallTo(() => ((IQueryable)fakeDbSet).Provider).Returns(profiles.Provider); + A.CallTo(() => ((IQueryable)fakeDbSet).Expression).Returns(profiles.Expression); + A.CallTo(() => ((IQueryable)fakeDbSet).ElementType).Returns(profiles.ElementType); + A.CallTo(() => ((IEnumerable)fakeDbSet).GetEnumerator()).Returns(profiles.GetEnumerator()); A.CallTo(() => userContext.Profiles) .Returns(fakeDbSet); diff --git a/tests/EdFi.Ods.WebApi.CompositeSpecFlowTests/EdFi.Ods.WebApi.CompositeSpecFlowTests.csproj b/tests/EdFi.Ods.WebApi.CompositeSpecFlowTests/EdFi.Ods.WebApi.CompositeSpecFlowTests.csproj index 9feea73676..f85000d6ff 100644 --- a/tests/EdFi.Ods.WebApi.CompositeSpecFlowTests/EdFi.Ods.WebApi.CompositeSpecFlowTests.csproj +++ b/tests/EdFi.Ods.WebApi.CompositeSpecFlowTests/EdFi.Ods.WebApi.CompositeSpecFlowTests.csproj @@ -31,7 +31,7 @@ - + diff --git a/tests/EdFi.Ods.WebApi.IntegrationTests/EdFi.Ods.WebApi.IntegrationTests.csproj b/tests/EdFi.Ods.WebApi.IntegrationTests/EdFi.Ods.WebApi.IntegrationTests.csproj index 51c07e4299..24ccd23005 100644 --- a/tests/EdFi.Ods.WebApi.IntegrationTests/EdFi.Ods.WebApi.IntegrationTests.csproj +++ b/tests/EdFi.Ods.WebApi.IntegrationTests/EdFi.Ods.WebApi.IntegrationTests.csproj @@ -22,7 +22,7 @@ - + diff --git a/tests/EdFi.TestFixture/DbContextExtensions.cs b/tests/EdFi.TestFixture/DbContextExtensions.cs index 76b191afce..335d2cf3eb 100644 --- a/tests/EdFi.TestFixture/DbContextExtensions.cs +++ b/tests/EdFi.TestFixture/DbContextExtensions.cs @@ -4,9 +4,8 @@ // See the LICENSE and NOTICES files in the project root for more information. using System; -using System.Data.Entity; -using System.Data.Entity.Validation; -using System.Linq; +using System.ComponentModel.DataAnnotations; +using Microsoft.EntityFrameworkCore; namespace EdFi.TestFixture { @@ -23,16 +22,11 @@ public static void CatchAndWriteDbValidationExceptions(Action action) { action(); } - catch (DbEntityValidationException exception) + catch (ValidationException exception) { - var errorTexts = - exception.EntityValidationErrors.SelectMany(x => x.ValidationErrors) - .Select(x => x.ErrorMessage); - - foreach (var error in errorTexts) - { - Console.WriteLine(error); - } + var errorTexts = exception.ValidationResult.ErrorMessage; + + Console.WriteLine(errorTexts); throw; } diff --git a/tests/EdFi.TestFixture/EdFi.TestFixture.csproj b/tests/EdFi.TestFixture/EdFi.TestFixture.csproj index 9734ed5147..7217142cdd 100644 --- a/tests/EdFi.TestFixture/EdFi.TestFixture.csproj +++ b/tests/EdFi.TestFixture/EdFi.TestFixture.csproj @@ -11,8 +11,10 @@ DEBUG;TRACE - + + + diff --git a/tests/EdFi.TestFixture/TestDbSet.cs b/tests/EdFi.TestFixture/TestDbSet.cs deleted file mode 100644 index da6d1a0321..0000000000 --- a/tests/EdFi.TestFixture/TestDbSet.cs +++ /dev/null @@ -1,226 +0,0 @@ -// 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; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Data.Entity; -using System.Data.Entity.Infrastructure; -using System.Linq; -using System.Linq.Expressions; -using System.Threading; -using System.Threading.Tasks; - -namespace EdFi.TestFixture -{ - /// - /// This class may used as a double for any DBSet. - /// Use it with a context interface - /// - /// public class TestContext : IBloggingContext - /// { - /// public TestContext() - /// { - /// this.Blogs = new TestDbSet<Blog>(); - /// this.Posts = new TestDbSet<Post>(); - /// } - /// - /// public DbSet<Blog> Blogs { get; set; } - /// public DbSet<Post> Posts { get; set; } - /// public int SaveChangesCount { get; private set; } - /// public int SaveChanges() - /// { - /// this.SaveChangesCount++; - /// return 1; - /// } - /// } - /// - /// - /// - public class TestDbSet : DbSet, IQueryable, IEnumerable, IDbAsyncEnumerable - where TEntity : class - { - private readonly ObservableCollection _data; - private readonly IQueryable _query; - - public TestDbSet() - { - _data = new ObservableCollection(); - _query = _data.AsQueryable(); - } - - public override ObservableCollection Local - { - get { return _data; } - } - - IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator() - { - return new TestDbAsyncEnumerator(_data.GetEnumerator()); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return _data.GetEnumerator(); - } - - Type IQueryable.ElementType - { - get { return _query.ElementType; } - } - - Expression IQueryable.Expression - { - get { return _query.Expression; } - } - - IQueryProvider IQueryable.Provider - { - get { return new TestDbAsyncQueryProvider(_query.Provider); } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return _data.GetEnumerator(); - } - - public override TEntity Add(TEntity item) - { - _data.Add(item); - return item; - } - - public override IEnumerable AddRange(IEnumerable entities) - { - var tmpEntities = entities.ToArray(); - - foreach (var entity in tmpEntities) - { - _data.Add(entity); - } - - return tmpEntities; - } - - public override TEntity Remove(TEntity item) - { - _data.Remove(item); - return item; - } - - public override TEntity Attach(TEntity item) - { - _data.Add(item); - return item; - } - - public override TEntity Create() - { - return Activator.CreateInstance(); - } - - public override TDerivedEntity Create() - { - return Activator.CreateInstance(); - } - } - - internal class TestDbAsyncQueryProvider : IDbAsyncQueryProvider - { - private readonly IQueryProvider _inner; - - internal TestDbAsyncQueryProvider(IQueryProvider inner) - { - _inner = inner; - } - - public IQueryable CreateQuery(Expression expression) - { - return new TestDbAsyncEnumerable(expression); - } - - public IQueryable CreateQuery(Expression expression) - { - return new TestDbAsyncEnumerable(expression); - } - - public object Execute(Expression expression) - { - return _inner.Execute(expression); - } - - public TResult Execute(Expression expression) - { - return _inner.Execute(expression); - } - - public Task ExecuteAsync(Expression expression, CancellationToken cancellationToken) - { - return Task.FromResult(Execute(expression)); - } - - public Task ExecuteAsync(Expression expression, CancellationToken cancellationToken) - { - return Task.FromResult(Execute(expression)); - } - } - - internal class TestDbAsyncEnumerable : EnumerableQuery, IDbAsyncEnumerable, IQueryable - { - public TestDbAsyncEnumerable(IEnumerable enumerable) - : base(enumerable) { } - - public TestDbAsyncEnumerable(Expression expression) - : base(expression) { } - - public IDbAsyncEnumerator GetAsyncEnumerator() - { - return new TestDbAsyncEnumerator( - this.AsEnumerable() - .GetEnumerator()); - } - - IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator() - { - return GetAsyncEnumerator(); - } - - IQueryProvider IQueryable.Provider - { - get { return new TestDbAsyncQueryProvider(this); } - } - } - - internal class TestDbAsyncEnumerator : IDbAsyncEnumerator - { - private readonly IEnumerator _inner; - - public TestDbAsyncEnumerator(IEnumerator inner) - { - _inner = inner; - } - - public void Dispose() - { - _inner.Dispose(); - } - - public Task MoveNextAsync(CancellationToken cancellationToken) - { - return Task.FromResult(_inner.MoveNext()); - } - - public T Current - { - get { return _inner.Current; } - } - - object IDbAsyncEnumerator.Current - { - get { return Current; } - } - } -}