Skip to content

Commit

Permalink
Version 8.0.1 - fixed issue #30
Browse files Browse the repository at this point in the history
  • Loading branch information
JonPSmith committed Dec 2, 2023
1 parent 4d602c1 commit 91d12a9
Show file tree
Hide file tree
Showing 10 changed files with 308 additions and 10 deletions.
29 changes: 29 additions & 0 deletions DataLayer/SchemaDb/AppDbContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) 2020 Jon P Smith, GitHub: JonPSmith, web: http://www.thereformedprogrammer.net/
// Licensed under MIT license. See License.txt in the project root for license information.

using DataLayer.SchemaDb;
using Microsoft.EntityFrameworkCore;

namespace MyFirstEfCoreApp
{
public class AppDbContext : DbContext
{
private const string ConnectionString = //#A
@"Server=(localdb)\mssqllocaldb;
Database=MyFirstEfCoreDb;
Trusted_Connection=True";

public DbSet<Book> Books { get; set; }

protected override void OnConfiguring(
DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(ConnectionString); //#B
}
}

/********************************************************
#A The connection string is used by the SQL Server database provider to find the database
#B Using the SQL Server database provider’s UseSqlServer command sets up the options ready for creating the applications’s DBContext
********************************************************/
}
16 changes: 16 additions & 0 deletions DataLayer/SchemaDb/Author.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) 2020 Jon P Smith, GitHub: JonPSmith, web: http://www.thereformedprogrammer.net/
// Licensed under MIT license. See License.txt in the project root for license information.

namespace DataLayer.SchemaDb
{
public class Author
{
public int AuthorId { get; set; } //#D
public string Name { get; set; }
public string WebUrl { get; set; }
}

/*******************************************************
#D This holds the Primary Key of the Author row in the database
* ************************************************/
}
27 changes: 27 additions & 0 deletions DataLayer/SchemaDb/Book.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) 2020 Jon P Smith, GitHub: JonPSmith, web: http://www.thereformedprogrammer.net/
// Licensed under MIT license. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;

namespace DataLayer.SchemaDb
{
public class Book
{
public int BookId { get; set; }

public string Title { get; set; }
public string Description { get; set; }
public DateTime PublishedOn { get; set; }


//-----------------------------------------
//one-to-one relationships

public int AuthorId { get; set; }
public Author Author { get; set; }

//many-to-many relationships
public ICollection<Book> Books { get; set; }
}
}
20 changes: 20 additions & 0 deletions DataLayer/SchemaDb/Review.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (c) 2020 Jon P Smith, GitHub: JonPSmith, web: http://www.thereformedprogrammer.net/
// Licensed under MIT license. See License.txt in the project root for license information.

using System.Collections.Generic;

namespace DataLayer.SchemaDb
{
public class Review
{
public int ReviewId { get; set; }

public int NumStars { get; set; }

//-----------------------------------------
//many-to-many relationships

public ICollection<Book> Books { get; set; }
}

}
24 changes: 24 additions & 0 deletions DataLayer/SchemaDb/SchemaDbContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) 2023 Jon P Smith, GitHub: JonPSmith, web: http://www.thereformedprogrammer.net/
// Licensed under MIT license. See License.txt in the project root for license information.

using Microsoft.EntityFrameworkCore;

namespace DataLayer.SchemaDb;

public class SchemaDbContext : DbContext
{
public SchemaDbContext(DbContextOptions<SchemaDbContext> options)
: base(options) { }

public DbSet<Book> Books { get; set; }
public DbSet<Author> Authors { get; set; }
public DbSet<Review> Reviews { get; set; }

protected override void
OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Book>().ToTable("SchemaTest");
modelBuilder.Entity<Author>().ToTable("SchemaTest", "Schema1");
modelBuilder.Entity<Review>().ToTable("SchemaTest", "Schema2");
}
}
6 changes: 3 additions & 3 deletions EfSchemaCompare/CompareEfSql.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Microsoft.EntityFrameworkCore.Scaffolding;
using Microsoft.EntityFrameworkCore.Scaffolding.Metadata;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;

namespace EfSchemaCompare
{
Expand Down Expand Up @@ -122,15 +123,14 @@ private void RemoveAnyTableToIgnore(DatabaseModel databaseModel, DbContext[] con
}
else
{

foreach (var tableToIgnore in _config.TablesToIgnoreCommaDelimited.Split(',')
.Select(x => x.Trim()).Where(x => !string.IsNullOrEmpty(x)))
{
var split = tableToIgnore.Split('.').Select(x => x.Trim()).ToArray();
var schema = split.Length == 1 ? databaseModel.DefaultSchema : split[0];
var schemaName = split.Length == 1 ? databaseModel.DefaultSchema : split[0];
var tableName = split.Length == 1 ? split[0] : split[1];
var tableToRemove = databaseModel.Tables
.SingleOrDefault(x => x.Schema?.Equals(schema, StringComparison.InvariantCultureIgnoreCase) ?? schema == null
.SingleOrDefault(x => (x.Schema ?? "").Equals(schemaName ?? "", StringComparison.InvariantCultureIgnoreCase)
&& x.Name.Equals(tableName, StringComparison.InvariantCultureIgnoreCase));
if (tableToRemove == null)
throw new InvalidOperationException(
Expand Down
11 changes: 4 additions & 7 deletions EfSchemaCompare/EfSchemaCompare.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,15 @@

<PropertyGroup>
<PackageId>EfCore.SchemaCompare</PackageId>
<PackageVersion>8.0.0</PackageVersion>
<Version>8.0.0</Version>
<AssemblyVersion>8.0.0</AssemblyVersion>
<PackageVersion>8.0.1</PackageVersion>
<Version>8.0.1</Version>
<AssemblyVersion>8.0.1</AssemblyVersion>
<FileVersion>8.0.0</FileVersion>
<Authors>Jon P Smith</Authors>
<Description>Useful tool if you are changing the schema of your database's schema outside of EF Core' migrations, say by using SQL change scripts. See readme file on github.</Description>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<PackageReleaseNotes>
- Supports .NET 8
- NEW FEATURE: Now compares all EF Core database providers, but some database providers may show incorrect match errors
- BREAKING CHANGE: You need to add the Microsoft.EntityFrameworkCore.Design NuGet to the application that uses this library
- Bug Fix: Fix to issue #21
- Fixed problems with TablesToIgnoreCommaDelimited with databases not supporting schema - see issue #30
</PackageReleaseNotes>
<Copyright>Copyright (c) 2020 Jon P Smith. Licenced under MIT licence</Copyright>
<PackageTags>Entity Framework Core, Database</PackageTags>
Expand Down
4 changes: 4 additions & 0 deletions ReleaseNotes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Release notes

## 8.0.1

- Fixed problems with TablesToIgnoreCommaDelimited with databases not supporting schema - see issue #30

## 8.0.0

- Supports .NET 8
Expand Down
2 changes: 2 additions & 0 deletions Test/UnitTests/TestCompareSqlite.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public TestCompareSqlite(ITestOutputHelper output)
_output = output;
}

//NOTE: SchemaCompare doesn't work with Sqlite because the Model data isn't correct
//But it doesn't throw an exception.
[Fact]
public void CompareEfSqlSqlite()
{
Expand Down
179 changes: 179 additions & 0 deletions Test/UnitTests/TestSchemas.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
// Copyright (c) 2023 Jon P Smith, GitHub: JonPSmith, web: http://www.thereformedprogrammer.net/
// Licensed under MIT license. See License.txt in the project root for license information.

using System;
using DataLayer.MyEntityDb;
using DataLayer.SchemaDb;
using EfSchemaCompare;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore;
using TestSupport.EfHelpers;
using TestSupport.Helpers;
using Xunit;
using Xunit.Abstractions;
using Xunit.Extensions.AssertExtensions;

namespace Test.UnitTests;

public class TestSchemas
{
private readonly ITestOutputHelper _output;

public TestSchemas(ITestOutputHelper output)
{
_output = output;
}

[Fact]
public void CompareEfSqlServer()
{
//SETUP
var options = this.CreateUniqueClassOptions<SchemaDbContext>();
using var context = new SchemaDbContext(options);
context.Database.EnsureDeleted();
context.Database.EnsureCreated();

var comparer = new CompareEfSql();

//ATTEMPT
var hasErrors = comparer.CompareEfWithDb(context);

//VERIFY
hasErrors.ShouldBeFalse();
}

[Fact]
public void CompareEfSqlServerExcludeTableWithDefaultSchema()
{
//SETUP
var options = this.CreateUniqueClassOptions<SchemaDbContext>();
using var context = new SchemaDbContext(options);
context.Database.EnsureDeleted();
context.Database.EnsureCreated();

var config = new CompareEfSqlConfig
{
TablesToIgnoreCommaDelimited = "SchemaTest"
};
var comparer = new CompareEfSql(config);

//ATTEMPT
var hasErrors = comparer.CompareEfWithDb(context);

//VERIFY
_output.WriteLine(comparer.GetAllErrors);
hasErrors.ShouldBeTrue();
comparer.GetAllErrors.ShouldEqual("NOT IN DATABASE: Entity 'Book', table name. Expected = SchemaTest");
}

[Fact]
public void CompareEfSqlServerExcludeTableWithSchema()
{
//SETUP
var options = this.CreateUniqueClassOptions<SchemaDbContext>();
using var context = new SchemaDbContext(options);
context.Database.EnsureDeleted();
context.Database.EnsureCreated();

var config = new CompareEfSqlConfig
{
TablesToIgnoreCommaDelimited = "Schema2.SchemaTest"
};
var comparer = new CompareEfSql(config);

//ATTEMPT
var hasErrors = comparer.CompareEfWithDb(context);

//VERIFY
_output.WriteLine(comparer.GetAllErrors);
hasErrors.ShouldBeTrue();
comparer.GetAllErrors.ShouldEqual("NOT IN DATABASE: Entity 'Review', table name. Expected = Schema2.SchemaTest");
}

[Fact]
public void CompareEfSqlServerExcludeMultipleTables()
{
//SETUP
var options = this.CreateUniqueClassOptions<SchemaDbContext>();
using var context = new SchemaDbContext(options);
context.Database.EnsureDeleted();
context.Database.EnsureCreated();

var config = new CompareEfSqlConfig
{
TablesToIgnoreCommaDelimited = "SchemaTest,Schema1.SchemaTest , Schema2.SchemaTest "
};
var comparer = new CompareEfSql(config);

//ATTEMPT
var hasErrors = comparer.CompareEfWithDb(context);

//VERIFY
_output.WriteLine(comparer.GetAllErrors);
hasErrors.ShouldBeTrue();
comparer.GetAllErrors.ShouldEqual(@"NOT IN DATABASE: Entity 'Author', table name. Expected = Schema1.SchemaTest
NOT IN DATABASE: Entity 'Book', table name. Expected = SchemaTest
NOT IN DATABASE: Entity 'Review', table name. Expected = Schema2.SchemaTest");
}

[Fact]
public void CompareEfSqlServerExcludeBadTable()
{
//SETUP
var options = this.CreateUniqueClassOptions<SchemaDbContext>();
using var context = new SchemaDbContext(options);
context.Database.EnsureDeleted();
context.Database.EnsureCreated();

var config = new CompareEfSqlConfig
{
TablesToIgnoreCommaDelimited = "BadTableName"
};
var comparer = new CompareEfSql(config);

//ATTEMPT
try
{
comparer.CompareEfWithDb(context);
}
catch (Exception e)
{
e.Message.ShouldEqual("The TablesToIgnoreCommaDelimited config property contains a table name of 'BadTableName', which was not found in the database");
return;
}

//VERIFY
true.ShouldBeFalse();
}

[Fact]
public void CompareEfPostgreSqlExcludeMultipleTables()
{
//SETUP
var options = this.CreatePostgreSqlUniqueClassOptions<SchemaDbContext>(
builder =>
{
builder.UseNpgsql(this.GetUniquePostgreSqlConnectionString(),
o => o.SetPostgresVersion(12, 0));
});
using var context = new SchemaDbContext(options);
context.Database.EnsureDeleted();
context.Database.EnsureCreated();

var config = new CompareEfSqlConfig
{
TablesToIgnoreCommaDelimited = "SchemaTest,Schema1.SchemaTest , Schema2.SchemaTest "
};
var comparer = new CompareEfSql(config);

//ATTEMPT
var hasErrors = comparer.CompareEfWithDb(context);

//VERIFY
_output.WriteLine(comparer.GetAllErrors);
hasErrors.ShouldBeTrue();
comparer.GetAllErrors.ShouldEqual(@"NOT IN DATABASE: Entity 'Author', table name. Expected = Schema1.SchemaTest
NOT IN DATABASE: Entity 'Book', table name. Expected = SchemaTest
NOT IN DATABASE: Entity 'Review', table name. Expected = Schema2.SchemaTest");
}
}

0 comments on commit 91d12a9

Please sign in to comment.