From f094f3658c4c9d5689afcc9b87fcaf512ef3738a Mon Sep 17 00:00:00 2001 From: Laurents Meyer Date: Tue, 1 Dec 2020 21:52:00 +0100 Subject: [PATCH] Fix data and test infrastructure and scaffolding (#82) * Fix local references. * Optimize, fix and simplify JetDataReader. * Only scaffold objects if tables are available. * Fix test infrastructure. * Ignore Development.props in root folder. --- .gitignore | 2 +- Development.props | 26 --- Directory.Build.props | 2 +- src/EFCore.Jet.Data/JetDataReader.cs | 214 ++++++++++-------- src/EFCore.Jet.Odbc/EFCore.Jet.Odbc.csproj | 9 + src/EFCore.Jet.OleDb/EFCore.Jet.OleDb.csproj | 9 + .../Internal/JetDatabaseModelFactory.cs | 11 +- .../TestUtilities/JetDatabaseCleaner.cs | 60 ----- test/EFCore.Jet.Tests/EFCore.Jet.Tests.csproj | 4 + 9 files changed, 150 insertions(+), 187 deletions(-) delete mode 100644 Development.props diff --git a/.gitignore b/.gitignore index d7b765d..ae38a82 100644 --- a/.gitignore +++ b/.gitignore @@ -165,4 +165,4 @@ $RECYCLE.BIN/ /msbuild/Output /.vs/EntityFrameworkCore.Jet .idea -!/build/ \ No newline at end of file +Development.props \ No newline at end of file diff --git a/Development.props b/Development.props deleted file mode 100644 index 6836ac0..0000000 --- a/Development.props +++ /dev/null @@ -1,26 +0,0 @@ - - - - E:\Sources\EntityFrameworkCore-3.1 - - \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props index 8e20792..3f70b82 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,6 @@ - + EntityFrameworkCore.Jet diff --git a/src/EFCore.Jet.Data/JetDataReader.cs b/src/EFCore.Jet.Data/JetDataReader.cs index 4b56d59..83d4f30 100644 --- a/src/EFCore.Jet.Data/JetDataReader.cs +++ b/src/EFCore.Jet.Data/JetDataReader.cs @@ -1,6 +1,7 @@ using System; using System.Data; using System.Data.Common; +using System.IO; using System.Text; using System.Threading; @@ -49,13 +50,15 @@ namespace EntityFrameworkCore.Jet.Data public override bool GetBoolean(int ordinal) { var value = _wrappedDataReader.GetValue(ordinal); - if (JetConfiguration.UseDefaultValueOnDBNullConversionError) + + if (JetConfiguration.UseDefaultValueOnDBNullConversionError && + Convert.IsDBNull(value)) { - if (value is DBNull) return false; + return default; } + if (value is bool boolValue) return boolValue; - if (value is sbyte sbyteValue) return sbyteValue != 0; if (value is byte byteValue) @@ -80,14 +83,16 @@ namespace EntityFrameworkCore.Jet.Data public override byte GetByte(int ordinal) { - var value = GetValue(ordinal); - if (JetConfiguration.UseDefaultValueOnDBNullConversionError) + var value = _wrappedDataReader.GetValue(ordinal); + + if (JetConfiguration.UseDefaultValueOnDBNullConversionError && + Convert.IsDBNull(value)) { - if (value is DBNull) return 0; + return default; } + if (value is byte byteValue) return byteValue; - if (value is sbyte sbyteValue) return checked((byte) sbyteValue); if (value is short shortValue) @@ -104,36 +109,33 @@ namespace EntityFrameworkCore.Jet.Data return checked((byte) ulongValue); if (value is decimal decimalValue) return (byte) decimalValue; + return (byte) value; } public override long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length) - { - var value = _wrappedDataReader.GetValue(ordinal); - if (JetConfiguration.UseDefaultValueOnDBNullConversionError && value is DBNull) - { - return 0; - } - return _wrappedDataReader.GetBytes(ordinal, dataOffset, buffer, bufferOffset, length); - } + => JetConfiguration.UseDefaultValueOnDBNullConversionError && + _wrappedDataReader.IsDBNull(ordinal) + ? 0 + : _wrappedDataReader.GetBytes(ordinal, dataOffset, buffer, bufferOffset, length); public override char GetChar(int ordinal) { var value = _wrappedDataReader.GetValue(ordinal); - if (JetConfiguration.UseDefaultValueOnDBNullConversionError && value is DBNull) - { - return (char)0; - } - return (char) value; + return JetConfiguration.UseDefaultValueOnDBNullConversionError && + Convert.IsDBNull(value) + ? default + : (char) value; } public override long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length) { - var value = _wrappedDataReader.GetValue(ordinal); - if (JetConfiguration.UseDefaultValueOnDBNullConversionError && value is DBNull) + if (JetConfiguration.UseDefaultValueOnDBNullConversionError && + _wrappedDataReader.IsDBNull(ordinal)) { return 0; } + return _wrappedDataReader.GetChars(ordinal, dataOffset, buffer, bufferOffset, length); } @@ -143,11 +145,10 @@ namespace EntityFrameworkCore.Jet.Data public override DateTime GetDateTime(int ordinal) { var value = _wrappedDataReader.GetValue(ordinal); - if (JetConfiguration.UseDefaultValueOnDBNullConversionError && value is DBNull) - { - return new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified); - } - return _wrappedDataReader.GetDateTime(ordinal); + return JetConfiguration.UseDefaultValueOnDBNullConversionError && + Convert.IsDBNull(value) + ? default + : (DateTime) value; } public virtual TimeSpan GetTimeSpan(int ordinal) @@ -159,21 +160,19 @@ namespace EntityFrameworkCore.Jet.Data public override decimal GetDecimal(int ordinal) { var value = _wrappedDataReader.GetValue(ordinal); - if (JetConfiguration.UseDefaultValueOnDBNullConversionError && value is DBNull) - { - return 0; - } - return Convert.ToDecimal(value); + return JetConfiguration.UseDefaultValueOnDBNullConversionError && + Convert.IsDBNull(value) + ? default + : Convert.ToDecimal(value); } public override double GetDouble(int ordinal) { var value = _wrappedDataReader.GetValue(ordinal); - if (JetConfiguration.UseDefaultValueOnDBNullConversionError && value is DBNull) - { - return 0; - } - return Convert.ToDouble(value); + return JetConfiguration.UseDefaultValueOnDBNullConversionError && + Convert.IsDBNull(value) + ? default + : Convert.ToDouble(value); } public override System.Collections.IEnumerator GetEnumerator() @@ -185,63 +184,52 @@ namespace EntityFrameworkCore.Jet.Data public override float GetFloat(int ordinal) { var value = _wrappedDataReader.GetValue(ordinal); - if (JetConfiguration.UseDefaultValueOnDBNullConversionError && value is DBNull) - { - return 0; - } - return Convert.ToSingle(value); + return JetConfiguration.UseDefaultValueOnDBNullConversionError && + Convert.IsDBNull(value) + ? default + : Convert.ToSingle(value); } public override Guid GetGuid(int ordinal) { // Fix for discussion https://jetentityframeworkprovider.codeplex.com/discussions/647028 var value = _wrappedDataReader.GetValue(ordinal); - if (JetConfiguration.UseDefaultValueOnDBNullConversionError && value is DBNull) - { - return Guid.Empty; - } - if (value is byte[]) - return new Guid((byte[]) value); - else - return _wrappedDataReader.GetGuid(ordinal); + return JetConfiguration.UseDefaultValueOnDBNullConversionError && + Convert.IsDBNull(value) + ? Guid.Empty + : value is byte[] bytes + ? new Guid(bytes) + : (Guid)value; } public override short GetInt16(int ordinal) { var value = _wrappedDataReader.GetValue(ordinal); - if (JetConfiguration.UseDefaultValueOnDBNullConversionError && value is DBNull) - { - return 0; - } - return Convert.ToInt16(value); + return JetConfiguration.UseDefaultValueOnDBNullConversionError && + Convert.IsDBNull(value) + ? default + : Convert.ToInt16(value); } public override int GetInt32(int ordinal) { // Fix for discussion https://jetentityframeworkprovider.codeplex.com/discussions/647028 var value = _wrappedDataReader.GetValue(ordinal); - if (JetConfiguration.UseDefaultValueOnDBNullConversionError && value is DBNull) - { - return 0; - } - else if (value is string) - { - var buffer = Encoding.Unicode.GetBytes((string)value); - var intValue = BitConverter.ToInt32(buffer, 0); - return intValue; - } - else - return Convert.ToInt32(value); + return JetConfiguration.UseDefaultValueOnDBNullConversionError && + Convert.IsDBNull(value) + ? default + : value is string stringValue + ? BitConverter.ToInt32(Encoding.Unicode.GetBytes(stringValue), 0) + : Convert.ToInt32(value); } public override long GetInt64(int ordinal) { var value = _wrappedDataReader.GetValue(ordinal); - if (JetConfiguration.UseDefaultValueOnDBNullConversionError && value is DBNull) - { - return 0; - } - return Convert.ToInt64(value); + return JetConfiguration.UseDefaultValueOnDBNullConversionError && + Convert.IsDBNull(value) + ? default + : Convert.ToInt64(value); } public override string GetName(int ordinal) @@ -249,35 +237,76 @@ namespace EntityFrameworkCore.Jet.Data public override int GetOrdinal(string name) => _wrappedDataReader.GetOrdinal(name); - + public override DataTable GetSchemaTable() => _wrappedDataReader.GetSchemaTable(); public override string GetString(int ordinal) { var value = _wrappedDataReader.GetValue(ordinal); - if (JetConfiguration.UseDefaultValueOnDBNullConversionError && value is DBNull) - { - return ""; - } - return _wrappedDataReader.GetString(ordinal); + return JetConfiguration.UseDefaultValueOnDBNullConversionError && + Convert.IsDBNull(value) + ? string.Empty + : (string) value; } public override object GetValue(int ordinal) - => _wrappedDataReader.GetValue(ordinal); - - public override T GetFieldValue(int ordinal) { - if (typeof(T) == typeof(TimeSpan)) - return (T) (object) GetTimeSpan(ordinal); - else if (typeof(T) == typeof(DateTimeOffset)) - return (T) (object) GetDateTimeOffset(ordinal); - else - return base.GetFieldValue(ordinal); + var fieldType = GetFieldType(ordinal); + + if (fieldType == typeof(bool)) + return GetBoolean(ordinal); + if (fieldType == typeof(byte)) + return GetByte(ordinal); + // if (fieldType == typeof(sbyte)) + // return GetSByte(ordinal); + if (fieldType == typeof(short)) + return GetInt16(ordinal); + // if (fieldType == typeof(ushort)) + // return GetUInt16(ordinal); + if (fieldType == typeof(int)) + return GetInt32(ordinal); + // if (fieldType == typeof(uint)) + // return GetUInt32(ordinal); + if (fieldType == typeof(long)) + return GetInt64(ordinal); + // if (fieldType == typeof(ulong)) + // return GetUInt64(ordinal); + if (fieldType == typeof(char)) + return GetChar(ordinal); + if (fieldType == typeof(decimal)) + return GetDecimal(ordinal); + if (fieldType == typeof(double)) + return GetDouble(ordinal); + if (fieldType == typeof(float)) + return GetFloat(ordinal); + if (fieldType == typeof(string)) + return GetString(ordinal); + if (fieldType == typeof(DateTime)) + return GetDateTime(ordinal); + if (fieldType == typeof(DateTimeOffset)) + return GetDateTimeOffset(ordinal); + if (fieldType == typeof(Guid)) + return GetGuid(ordinal); + if (fieldType == typeof(Stream)) + return GetStream(ordinal); + if (fieldType == typeof(TextReader) || fieldType == typeof(StringReader)) + return GetTextReader(ordinal); + if (fieldType == typeof(TimeSpan)) + return GetTimeSpan(ordinal); + + return _wrappedDataReader.GetValue(ordinal); } public override int GetValues(object[] values) - => _wrappedDataReader.GetValues(values); + { + var count = Math.Min((values ?? throw new ArgumentNullException(nameof(values))).Length, FieldCount); + + for (var i = 0; i < count; i++) + values[i] = GetValue(i); + + return count; + } public override bool HasRows => _wrappedDataReader.HasRows; @@ -286,13 +315,8 @@ namespace EntityFrameworkCore.Jet.Data => _wrappedDataReader.IsClosed; public override bool IsDBNull(int ordinal) - { - if (_wrappedDataReader.IsDBNull(ordinal)) - return true; - if (JetConfiguration.IntegerNullValue != null && ((int) JetConfiguration.IntegerNullValue).Equals(_wrappedDataReader.GetValue(ordinal))) - return true; - return false; - } + => _wrappedDataReader.IsDBNull(ordinal) || + JetConfiguration.IntegerNullValue != null && ((int) JetConfiguration.IntegerNullValue).Equals(GetValue(ordinal)); public override bool NextResult() => _wrappedDataReader.NextResult(); diff --git a/src/EFCore.Jet.Odbc/EFCore.Jet.Odbc.csproj b/src/EFCore.Jet.Odbc/EFCore.Jet.Odbc.csproj index ab39b4a..c449c75 100644 --- a/src/EFCore.Jet.Odbc/EFCore.Jet.Odbc.csproj +++ b/src/EFCore.Jet.Odbc/EFCore.Jet.Odbc.csproj @@ -20,4 +20,13 @@ + + + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(DefaultNetStandardTargetFramework)\Microsoft.EntityFrameworkCore.dll + + + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(DefaultNetStandardTargetFramework)\Microsoft.EntityFrameworkCore.Abstractions.dll + + + diff --git a/src/EFCore.Jet.OleDb/EFCore.Jet.OleDb.csproj b/src/EFCore.Jet.OleDb/EFCore.Jet.OleDb.csproj index 7f6ea44..97ce6f5 100644 --- a/src/EFCore.Jet.OleDb/EFCore.Jet.OleDb.csproj +++ b/src/EFCore.Jet.OleDb/EFCore.Jet.OleDb.csproj @@ -20,4 +20,13 @@ + + + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(DefaultNetStandardTargetFramework)\Microsoft.EntityFrameworkCore.dll + + + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(DefaultNetStandardTargetFramework)\Microsoft.EntityFrameworkCore.Abstractions.dll + + + diff --git a/src/EFCore.Jet/Scaffolding/Internal/JetDatabaseModelFactory.cs b/src/EFCore.Jet/Scaffolding/Internal/JetDatabaseModelFactory.cs index 0cf3fc1..ec58843 100644 --- a/src/EFCore.Jet/Scaffolding/Internal/JetDatabaseModelFactory.cs +++ b/src/EFCore.Jet/Scaffolding/Internal/JetDatabaseModelFactory.cs @@ -164,10 +164,13 @@ namespace EntityFrameworkCore.Jet.Scaffolding.Internal } } } - - GetColumns(connection, tables); - GetIndexes(connection, tables); - GetRelations(connection, tables); + + if (tables.Count > 0) + { + GetColumns(connection, tables); + GetIndexes(connection, tables); + GetRelations(connection, tables); + } return tables; } diff --git a/test/EFCore.Jet.FunctionalTests/TestUtilities/JetDatabaseCleaner.cs b/test/EFCore.Jet.FunctionalTests/TestUtilities/JetDatabaseCleaner.cs index 6de97d8..0bf9507 100644 --- a/test/EFCore.Jet.FunctionalTests/TestUtilities/JetDatabaseCleaner.cs +++ b/test/EFCore.Jet.FunctionalTests/TestUtilities/JetDatabaseCleaner.cs @@ -2,11 +2,8 @@ using System.Diagnostics; using Microsoft.EntityFrameworkCore.Internal; -using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Scaffolding; -using Microsoft.EntityFrameworkCore.Scaffolding.Metadata; using EntityFrameworkCore.Jet.Diagnostics.Internal; -using EntityFrameworkCore.Jet.Metadata.Internal; using EntityFrameworkCore.Jet.Scaffolding.Internal; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.TestUtilities; @@ -23,62 +20,5 @@ namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities new LoggingOptions(), new DiagnosticListener("Fake"), new JetLoggingDefinitions())); - - protected override bool AcceptTable(DatabaseTable table) => !(table is DatabaseView); - - protected override bool AcceptIndex(DatabaseIndex index) - => false; - - private readonly string _dropViewsSql = @" -DECLARE @name VARCHAR(MAX) = '__dummy__', @SQL VARCHAR(MAX) = ''; - -WHILE @name IS NOT NULL -BEGIN - SELECT @name = - (SELECT TOP 1 QUOTENAME(s.`name`) + '.' + QUOTENAME(o.`name`) - FROM sysobjects o - INNER JOIN sys.views v ON o.id = v.object_id - INNER JOIN sys.schemas s ON s.schema_id = v.schema_id - WHERE (s.name = 'dbo' OR s.principal_id <> s.schema_id) AND o.`type` = 'V' AND o.category = 0 AND o.`name` NOT IN - ( - SELECT referenced_entity_name - FROM sys.sql_expression_dependencies AS sed - INNER JOIN sys.objects AS o ON sed.referencing_id = o.object_id - ) - ORDER BY v.`name`) - - SELECT @SQL = 'DROP VIEW ' + @name - EXEC (@SQL) -END"; - - protected override string BuildCustomSql(DatabaseModel databaseModel) - => _dropViewsSql; - - protected override string BuildCustomEndingSql(DatabaseModel databaseModel) - => _dropViewsSql - + @" -GO - -DECLARE @SQL VARCHAR(MAX) = ''; -SELECT @SQL = @SQL + 'DROP FUNCTION ' + QUOTENAME(ROUTINE_SCHEMA) + '.' + QUOTENAME(ROUTINE_NAME) + ';' - FROM `INFORMATION_SCHEMA`.`ROUTINES` WHERE ROUTINE_TYPE = 'FUNCTION' AND ROUTINE_BODY = 'SQL'; -EXEC (@SQL); - -SET @SQL =''; -SELECT @SQL = @SQL + 'DROP AGGREGATE ' + QUOTENAME(ROUTINE_SCHEMA) + '.' + QUOTENAME(ROUTINE_NAME) + ';' - FROM `INFORMATION_SCHEMA`.`ROUTINES` WHERE ROUTINE_TYPE = 'FUNCTION' AND ROUTINE_BODY = 'EXTERNAL'; -EXEC (@SQL); - -SET @SQL =''; -SELECT @SQL = @SQL + 'DROP PROC ' + QUOTENAME(schema_name(schema_id)) + '.' + QUOTENAME(name) + ';' FROM sys.procedures; -EXEC (@SQL); - -SET @SQL =''; -SELECT @SQL = @SQL + 'DROP TYPE ' + QUOTENAME(schema_name(schema_id)) + '.' + QUOTENAME(name) + ';' FROM sys.types WHERE is_user_defined = 1; -EXEC (@SQL); - -SET @SQL =''; -SELECT @SQL = @SQL + 'DROP SCHEMA ' + QUOTENAME(name) + ';' FROM sys.schemas WHERE principal_id <> schema_id; -EXEC (@SQL);"; } } diff --git a/test/EFCore.Jet.Tests/EFCore.Jet.Tests.csproj b/test/EFCore.Jet.Tests/EFCore.Jet.Tests.csproj index cc86e0f..d292153 100644 --- a/test/EFCore.Jet.Tests/EFCore.Jet.Tests.csproj +++ b/test/EFCore.Jet.Tests/EFCore.Jet.Tests.csproj @@ -18,6 +18,10 @@ + + + +