Skip to content

Commit

Permalink
Added AlwaysRunStage2 (not tested)
Browse files Browse the repository at this point in the history
  • Loading branch information
JonPSmith committed Nov 8, 2024
1 parent 8884031 commit 3a9e29d
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 23 deletions.
5 changes: 4 additions & 1 deletion EfSchemaCompare/CompareEfSql.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,10 @@ private bool FinishRestOfCompare(string connectionString, DbContext[] dbContexts
hasErrors |= stage1Comparer.CompareModelToDatabase(databaseModel);
}

if (hasErrors) return true;
//Normally stage 2 isn't run if there were errors that haven't ignored,
//but if AlwaysRunStage2 is true, then stage 2 will run even there are non-ignored errors
if (!_config.AlwaysRunStage2 && hasErrors)
return true;

//No errors, so its worth running the second phase
var stage2Comparer = new Stage2Comparer(databaseModel, _config);
Expand Down
14 changes: 8 additions & 6 deletions EfSchemaCompare/CompareEfSqlConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ public class CompareEfSqlConfig
{
private readonly List<CompareLog> _logsToIgnore = new List<CompareLog>();

///// <summary>
///// Set this to StringComparer.CurrentCultureIgnoreCase to change the
///// This effects the table, schema, column, primary/index/foreignKey constraint names
///// </summary>
//NOTE Turned off CaseComparer as doesn't work with EF Core 5
//public StringComparer CaseComparer { get; set; } = StringComparer.CurrentCulture;
/// <summary>
/// By default, Stage 2 only runs if: either there were no errors in Stage 1, or if you
/// have suppressed all the errors in the first stage. But Stage 2 can be forced to run by either:
/// 1. Set <see cref="AlwaysRunStage2"/> to true
/// 2. Set <see cref="TablesToIgnoreCommaDelimited"/> to "", which says you want to check all tables
/// in the database against your DbContext(s).
/// </summary>
public bool AlwaysRunStage2 { get; set; } = false;

/// <summary>
/// This allows you to ignore tables that your EF Core context doesn't use. There are three settings
Expand Down
11 changes: 5 additions & 6 deletions EfSchemaCompare/EfSchemaCompare.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,15 @@

<PropertyGroup>
<PackageId>EfCore.SchemaCompare</PackageId>
<PackageVersion>8.1.0</PackageVersion>
<Version>8.1.0</Version>
<PackageVersion>8.2.0</PackageVersion>
<Version>8.2.0</Version>
<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>
- New feature: Checks Json Mapping data, see README for more. Limitation that only works with the default column name
- Fixed issue #18. i.e "columns that are extra in db are not excluded" is fixed
- IEntityType is obsolete, moved to ITypeBase - see https://github.com/dotnet/efcore/issues/34594
- Updated vunables NuGets System.Text.Json and Microsoft.Extensions.Caching.Memory
- The ExtraInDatabase errors didn't correctly say what part of the database (e.g. "Table", "Column") was extra. This is fixed.
- NOTE: If you have ignored some ExtraInDatabase errors you our old ignored ExtraInDatabase might need updating to the new (correct format) pattern.
- New boolean 'AlwaysRunStage2' in the CompareEfSqlConfig. If set to 'true', then Stage 2 will always run, even if there are non-ignored errors.
</PackageReleaseNotes>
<Copyright>Copyright (c) 2020 Jon P Smith. Licenced under MIT licence</Copyright>
<PackageTags>Entity Framework Core, Database</PackageTags>
Expand Down
25 changes: 18 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ The EfCore.SchemaCompare library (shortened to EfSchemaCompare in the documentat
_Thanks to GitHub @bgrauer-atacom and @lweberprb for suggesting that this library could support extra database providers. See the [issue #26](https://github.com/JonPSmith/EfCore.SchemaCompare/pull/26) to see the code that these two people provided to add this feature._

- Versions below 8 support:
- SqlServer
- Sqlite
- Npgsql.EntityFrameworkCore.PostgreSQL
- SqlServer
- Sqlite
- Npgsql.EntityFrameworkCore.PostgreSQL

## What does EfSchemaCompare check?

Expand Down Expand Up @@ -91,6 +91,8 @@ The fun part is comparing these two sources, especially with all the different t

![EfSchemaCompare diagram](https://github.com/JonPSmith/EfCore.SchemaCompare/blob/master/EfSchemaCompare.png)

The EfSchemaCompare uses two stages: Stage 1 checks your EF Core DbContext matches your database. Stage 2 checks your database for extra tables, columns, etc. that your EF Core DbContext doesn't use.

## How to use EfSchemaCompare

I usually run the EfSchemaCompare code in my unit tests, but that is up to you.
Expand Down Expand Up @@ -127,6 +129,7 @@ public void CompareViaContext()
- If no connection string is found in the `appsetting.json` file, or there is no `appsetting.json`, then it assumes the string is a connection string.

See below for an example of both of of these options:

```c#
[Fact]
public void CompareBookThenOrderAgainstBookOrderDatabaseViaAppSettings()
Expand Down Expand Up @@ -168,7 +171,7 @@ The error above says
Here is another error coming from stage 2 where it checks the database side, i.e., Unused Tables, Columns and Indexes

```text
EXTRA IN DATABASE: Table 'MyEntites', column name. Found = MyEntityId
EXTRA IN DATABASE: Table 'HeadEntries', column name. Found = DifferentColumnName
```

This says that there is a column called `MyEntityId` in the table `MyEntites` that hasn't got a property in the entity class mapped to the `MyEntites` table.
Expand All @@ -179,8 +182,6 @@ This says that there is a column called `MyEntityId` in the table `MyEntites` th

In a few cases you will get errors that aren't correct (see limitations) or not relevant. In these cases you might want to suppress those errors. There are two way to do this, with the first being the easiest. Both use the `CompareEfSqlConfig` class.

_NOTE: The stage 2 check only runs if: either there was no errors in the first stage, or if you have suppressed all the errors in the first stage._

### Suppress errors via `IgnoreTheseErrors`

In this approach you capture the error strings you want to ignore and return them as a string, with each error separated by the newline, `'\n'`, character. You feed the errors via the configuration's `IgnoreTheseErrors` method. See an example below
Expand Down Expand Up @@ -240,11 +241,14 @@ public void CompareSuppressViaViaAddIgnoreCompareLog()
//VERIFY
hasErrors.ShouldBeFalse(comparer.GetAllErrors);
}

```

## Other configuration options

You have already seen the class called `CompareEfSqlConfig` for suppressing errors, but there are two other configrations.

### `TablesToIgnoreCommaDelimited` string property

You have already seen the class called `CompareEfSqlConfig` for suppressing errors. There is one other configuration property called `TablesToIgnoreCommaDelimited`, which allows you to control what table/views in the database are considered.

By default (i.e. when `TablesToIgnoreCommaDelimited` is null) then `CompareEfSql` will only look at the tables/views in the database that your EF Core entity classes are mapped to. This provides an simple starting point. The other options are:
Expand All @@ -268,3 +272,10 @@ var config = new CompareEfSqlConfig
TablesToIgnoreCommaDelimited = "Orders,LineItem"
};
var comparer = new CompareEfSql(config);
```

### `AlwaysRunStage2` boolean property (v8.2.0 or later)

Getting all the errors in one go can be useful, for instance when you are creating a EF Core DbContext to match a given database. But by default, Stage 2 isn't run if Stage 1 found errors that haven't been register in `config.IgnoreTheseErrors(... your error strings ...)`.

In version 8.2.0 a new boolean property called `AlwaysRunStage2` in `CompareEfSqlConfig` and if you you set this to `true` then Stage 2 will always run, even if there are non-ignored errors. See [issue #38](https://github.com/JonPSmith/EfCore.SchemaCompare/issues/38) which made me add this new feature.
7 changes: 7 additions & 0 deletions ReleaseNotes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Release notes

## 8.2.0

- The ExtraInDatabase errors didn't correctly say what part of the database (e.g. "Table", "Column") was extra. This is fixed.
- NOTE: If you have ignored some ExtraInDatabase errors you our old ignored ExtraInDatabase might need updating to the new (correct format) pattern.
- New boolean 'AlwaysRunStage2' in the CompareEfSqlConfig. If set to 'true', then Stage 2 will always run, even if there are non-ignored errors. See issue #38, which made me add this new feature.


## 8.1.0

- New feature: Checks Json Mapping data, see README for more. Limitation that only works with the default column name
Expand Down
9 changes: 6 additions & 3 deletions Test/UnitTests/TestBookContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,12 @@ public void TestTagsOk()
var bTags = books.Select(x => new {
x.BookId,
tagsNames = string.Join(" | ", x.Tags.Select(y => y.TagId))

});
}).ToArray();
bTags.Length.ShouldEqual(4);
bTags[0].tagsNames.ShouldEqual("Editor's Choice | Refactoring");
bTags[1].tagsNames.ShouldEqual("Architecture");
bTags[2].tagsNames.ShouldEqual("Architecture | Editor's Choice");
bTags[3].tagsNames.ShouldEqual("Quantum Entanglement");
}

[Fact]
Expand Down Expand Up @@ -112,7 +116,6 @@ public void TestDatabaseTablesOk()
var options = this.CreateUniqueClassOptions<BookContext>();
using var context = new BookContext(options);
context.Database.EnsureClean();
context.Database.EnsureCreated();

//ATTEMPT
var factory = context.GetDatabaseModelFactory();
Expand Down
1 change: 1 addition & 0 deletions Test/UnitTests/TestExtraInDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public TestExtraInDatabase(ITestOutputHelper output)
[Fact]
public void DecodeCompareTextToCompareLog_ExtraIndexInDatabase_Test()
{
//See issue #39
var str = "EXTRA IN DATABASE: Index 'tenants', index constraint name. Found = ix_tenants_belongs_to_database_instance_id";
var compareLog = FindErrorsToIgnore.DecodeCompareTextToCompareLog(str);
compareLog.Type.ShouldEqual(CompareType.Index);
Expand Down

0 comments on commit 3a9e29d

Please sign in to comment.