JonPSmith / EfCore.TestSupport

Tools for helping in unit testing applications that use Entity Framework Core
https://www.thereformedprogrammer.net/new-features-for-unit-testing-your-entity-framework-core-5-code/
Other
352 stars 53 forks source link

Ability to compare only those tables that exist in the EF Context. #18

Closed dvoreckyaa closed 5 years ago

dvoreckyaa commented 5 years ago

I know that TablesToIgnoreCommaDelimited already exists, but I could not undertand how I had to use it properly. My contexts contains only a small amount of table. Should I have enumerate all tables from the DB, that do not exist in the context? So It would be greate to have such option to declare only required tables. I've impemented the following solution: Added new config properties:

        public bool CompareOnlyExistingTables { get; set; }
        internal string TablesToCompareCommaDelimited { get; set; }

Updated 2 methods:

private DatabaseModel GetDatabaseModelViaScaffolder(DbContext context, string configOrConnectionString, IDesignTimeServices designTimeService)
        {
            var serviceProvider = designTimeService.GetDesignTimeProvider();
            var factory = serviceProvider.GetService<IDatabaseModelFactory>();
            var connectionString = configOrConnectionString == null
                ? context.Database.GetDbConnection().ConnectionString
                : GetConfigurationOrActualString(configOrConnectionString);
            //FIXED
            _config.TablesToCompareCommaDelimited = _config.CompareOnlyExistingTables ? string.Join(",", context.Model.GetEntityTypes()
                                                                                                         .Select(r => string.IsNullOrEmpty(r.Relational().Schema) ? r.Relational().TableName :                                                                                                         $"{r.Relational().Schema}.{r.Relational().TableName}")) : string.Empty;
            var databaseModel = factory.Create(connectionString, new string[] { }, new string[] { });
            RemoveAnyTabletoIgnore(databaseModel);
            return databaseModel;
        }

        private void RemoveAnyTabletoIgnore(DatabaseModel databaseModel)
        {
            //FIXED
            List<DatabaseTable> CreateTableList(string list)
            {
                var tableList = new List<DatabaseTable>();
                foreach (var tableToIgnore in list.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 tableName = split.Length == 1 ? split[0] : split[1];
                    var tableToRemove = databaseModel.Tables
                        .SingleOrDefault(x => x.Schema.Equals(schema, StringComparison.InvariantCultureIgnoreCase)
                                           && x.Name.Equals(tableName, StringComparison.InvariantCultureIgnoreCase));
                    if (tableToRemove == null)
                        throw new InvalidOperationException(
                            $"The TablesToIgnoreCommaDelimited config property contains a table name of '{tableToIgnore}', which was not found in the database");
                    tableList.Add(tableToRemove);
                }
                return tableList;
            }
            if (_config.TablesToIgnoreCommaDelimited != null)
            {
                foreach (var tableToRemove in CreateTableList(_config.TablesToIgnoreCommaDelimited))
                {
                    databaseModel.Tables.Remove(tableToRemove);
                }
            }
            if (!string.IsNullOrEmpty(_config.TablesToCompareCommaDelimited))
            {
                var tablesToRemove = databaseModel.Tables.Where(r => !CreateTableList(_config.TablesToCompareCommaDelimited).Contains(r)).ToList();
                foreach (var tableToRemove in tablesToRemove)
                {
                    databaseModel.Tables.Remove(tableToRemove);
                }
            }
        }
JonPSmith commented 5 years ago

Hi @dvoreckyaa,

I have just released version 2.0.0 which, by default, only checks the tables that your EF Core classes map to. This is a breaking change, but should help you and others that only map part of a database.

See the comments on the TablesToIgnoreCommaDelimited property in the CompareEfSqlConfig for more info.

dvoreckyaa commented 5 years ago

Hi @JonPSmith it is great, thanks!