diff --git a/src/AdoNetCore.AseClient/AseCommandBuilder.cs b/src/AdoNetCore.AseClient/AseCommandBuilder.cs index 32ef1c0..63490a6 100644 --- a/src/AdoNetCore.AseClient/AseCommandBuilder.cs +++ b/src/AdoNetCore.AseClient/AseCommandBuilder.cs @@ -224,12 +224,15 @@ private static DataTable GetSchemaTableWithKeyInfo(DbCommand sourceCommand) if (dataTable != null) { // If there is no primary key on the table, then throw MissingPrimaryKeyException. - var isKeyColumn = dataTable.Columns["IsKey"]; + var isKeyColumn = dataTable.Columns[SchemaTableColumn.IsKey]; + var isUniqueColumn = dataTable.Columns[SchemaTableColumn.IsUnique]; + var hasKey = false; foreach (DataRow columnDescriptorRow in dataTable.Rows) { - hasKey |= (bool)columnDescriptorRow[isKeyColumn]; + hasKey |= (bool)columnDescriptorRow[isKeyColumn] || + (bool)columnDescriptorRow[isUniqueColumn]; if (hasKey) { diff --git a/src/AdoNetCore.AseClient/AseParameterCollection.cs b/src/AdoNetCore.AseClient/AseParameterCollection.cs index 5027c13..fdd7ad1 100644 --- a/src/AdoNetCore.AseClient/AseParameterCollection.cs +++ b/src/AdoNetCore.AseClient/AseParameterCollection.cs @@ -263,10 +263,10 @@ public AseParameter Add(string parameterName, AseDbType dbType, int size, Parame /// A new object. public AseParameter Add(AseParameter parameter) { - if (parameter != null) - { - _parameters.Add(parameter); - } + if (parameter == null) throw new ArgumentNullException(nameof(parameter)); + if (Contains(parameter)) throw new ArgumentException($"parameter name '{parameter.ParameterName}' is already in the collection"); + + _parameters.Add(parameter); return parameter; } @@ -379,6 +379,7 @@ public override int Add(object value) { if (value is AseParameter p) { + if (Contains(p)) throw new ArgumentException($"Parameter name: '{p.ParameterName}' is already registered", nameof(value)); return ((IList)_parameters).Add(p); } return -1; @@ -438,15 +439,23 @@ public override int IndexOf(object value) /// Returns -1 when the object does not exist in the . public int IndexOf(AseParameter value) { - if (value != null) + if (value == null) return -1; + for (var i = 0; i < _parameters.Count; i++) { - for (var i = 0; i < _parameters.Count; i++) + if (string.IsNullOrWhiteSpace(value.ParameterName)) { if (value == _parameters[i]) { return i; } } + else + { + if (value == _parameters[i] || value.ParameterName == _parameters[i].ParameterName) + { + return i; + } + } } return -1; @@ -459,6 +468,7 @@ public int IndexOf(AseParameter value) /// The object to add to the collection. public override void Insert(int index, object parameter) { + if (Contains(parameter)) throw new ArgumentException($"parameter name '{parameter}' is already in the collection"); ((IList)_parameters).Insert(index, parameter); } @@ -469,6 +479,7 @@ public override void Insert(int index, object parameter) /// The object to add to the collection. public void Insert(int index, AseParameter parameter) { + if (Contains(parameter)) throw new ArgumentException($"parameter name '{parameter.ParameterName}' is already in the collection"); ((IList)_parameters).Insert(index, parameter); } @@ -521,10 +532,7 @@ public override void RemoveAt(int index) /// The starting index of the array. public override void CopyTo(Array array, int index) { - if (array != null) - { - ((IList)_parameters).CopyTo(array, index); - } + ((IList)_parameters).CopyTo(array, index); } /// diff --git a/src/AdoNetCore.AseClient/Internal/FormatItem.cs b/src/AdoNetCore.AseClient/Internal/FormatItem.cs index d0b5a20..40f994d 100644 --- a/src/AdoNetCore.AseClient/Internal/FormatItem.cs +++ b/src/AdoNetCore.AseClient/Internal/FormatItem.cs @@ -66,11 +66,11 @@ public string ParameterName public static FormatItem CreateForParameter(AseParameter parameter, DbEnvironment env, AseCommand command) { + parameter.AseDbType = TypeMap.InferType(parameter); + var dbType = parameter.DbType; var length = TypeMap.GetFormatLength(dbType, parameter, env.Encoding); - parameter.AseDbType = TypeMap.InferType(parameter); - var format = command.FormatItem; var parameterName = parameter.ParameterName ?? command.Parameters.IndexOf(parameter).ToString(); if (!(command.FormatItem != null && command.FormatItem.ParameterName == parameterName && diff --git a/src/AdoNetCore.AseClient/Internal/SchemaTableBuilder.cs b/src/AdoNetCore.AseClient/Internal/SchemaTableBuilder.cs index 29b88a0..6298f58 100644 --- a/src/AdoNetCore.AseClient/Internal/SchemaTableBuilder.cs +++ b/src/AdoNetCore.AseClient/Internal/SchemaTableBuilder.cs @@ -130,17 +130,12 @@ private FillTableResults FillTableFromFormats(DataTable table) private void TryLoadKeyInfo(DataTable table, string baseTableNameValue, string baseSchemaNameValue, string baseCatalogNameValue) { if (_connection == null) - { throw new InvalidOperationException("Invalid AseCommand.Connection"); - } if (_connection.State != ConnectionState.Open) - { throw new InvalidOperationException("Invalid AseCommand.Connection.ConnectionState"); - } - if (!string.IsNullOrWhiteSpace(baseTableNameValue) && - !string.IsNullOrWhiteSpace(baseCatalogNameValue)) + if (string.IsNullOrWhiteSpace(baseTableNameValue)) return; using (var command = _connection.CreateCommand()) diff --git a/test/AdoNetCore.AseClient.Tests/Integration/AseCommandTests.cs b/test/AdoNetCore.AseClient.Tests/Integration/AseCommandTests.cs index 0ffdac3..83888ba 100644 --- a/test/AdoNetCore.AseClient.Tests/Integration/AseCommandTests.cs +++ b/test/AdoNetCore.AseClient.Tests/Integration/AseCommandTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Data; using System.Xml; using AdoNetCore.AseClient.Internal; using AdoNetCore.AseClient.Tests.Util; @@ -236,28 +237,45 @@ public void Command_Reuse_ShouldWork_For_NonNull_Value(System.Data.DbType dbType } } } + + [Test] + public void Command_Duplicate_Parameter_Name_Should_Throws_ArgumentException() + { + using (var connection = GetConnection()) + { + connection.Open(); + var sql = "select @p1, @p2"; + var aseCommand = connection.CreateCommand(); + aseCommand.CommandText = sql; + aseCommand.CommandType = CommandType.Text; + aseCommand.Parameters.Add("@p1", "test"); + aseCommand.Parameters.Add("@p2", "test2"); + Assert.Throws(() => aseCommand.Parameters.Add("@p1", "test3")); + } + } + private static IEnumerable ReUseCommandTypeData() { - yield return new TestCaseData(System.Data.DbType.Boolean, typeof(bool), false); - yield return new TestCaseData(System.Data.DbType.Byte, typeof(byte), 12); - yield return new TestCaseData(System.Data.DbType.SByte, typeof(sbyte), 2); - yield return new TestCaseData(System.Data.DbType.Int16, typeof(short), 3); - yield return new TestCaseData(System.Data.DbType.UInt16, typeof(ushort), 4); - yield return new TestCaseData(System.Data.DbType.Int32, typeof(int), 23); - yield return new TestCaseData(System.Data.DbType.UInt32, typeof(uint), 45); - yield return new TestCaseData(System.Data.DbType.Int64, typeof(long), 76434755); - yield return new TestCaseData(System.Data.DbType.UInt64, typeof(ulong), 1223); - yield return new TestCaseData(System.Data.DbType.String, typeof(string), "If it could only be like this always—always summer, always alone, the fruit always ripe"); - yield return new TestCaseData(System.Data.DbType.AnsiString, typeof(string), "Doubt thou the stars are fire; Doubt that the sun doth move; Doubt truth to be a liar; But never doubt I love"); - yield return new TestCaseData(System.Data.DbType.AnsiStringFixedLength, typeof(string), "For never was a story of more woe than this of Juliet and her Romeo."); - yield return new TestCaseData(System.Data.DbType.Guid, typeof(string), "e2207b47-3fce-4187-808f-e206398a9133"); - yield return new TestCaseData(System.Data.DbType.Decimal, typeof(decimal), 342.23); - yield return new TestCaseData(System.Data.DbType.Currency, typeof(decimal), 1233.3); - yield return new TestCaseData(System.Data.DbType.Single, typeof(float), 20.34f); - yield return new TestCaseData(System.Data.DbType.Double, typeof(double), 3423.234d); - yield return new TestCaseData(System.Data.DbType.DateTime, typeof(DateTime), "2019-03-13 03:20:35.23 AM"); - yield return new TestCaseData(System.Data.DbType.Date, typeof(DateTime), "2018-07-04 23:20:35.23 PM"); - yield return new TestCaseData(System.Data.DbType.Time, typeof(DateTime), "2014-09-10 23:20:35"); + yield return new TestCaseData(DbType.Boolean, typeof(bool), false); + yield return new TestCaseData(DbType.Byte, typeof(byte), 12); + yield return new TestCaseData(DbType.SByte, typeof(sbyte), 2); + yield return new TestCaseData(DbType.Int16, typeof(short), 3); + yield return new TestCaseData(DbType.UInt16, typeof(ushort), 4); + yield return new TestCaseData(DbType.Int32, typeof(int), 23); + yield return new TestCaseData(DbType.UInt32, typeof(uint), 45); + yield return new TestCaseData(DbType.Int64, typeof(long), 76434755); + yield return new TestCaseData(DbType.UInt64, typeof(ulong), 1223); + yield return new TestCaseData(DbType.String, typeof(string), "If it could only be like this always—always summer, always alone, the fruit always ripe"); + yield return new TestCaseData(DbType.AnsiString, typeof(string), "Doubt thou the stars are fire; Doubt that the sun doth move; Doubt truth to be a liar; But never doubt I love"); + yield return new TestCaseData(DbType.AnsiStringFixedLength, typeof(string), "For never was a story of more woe than this of Juliet and her Romeo."); + yield return new TestCaseData(DbType.Guid, typeof(string), "e2207b47-3fce-4187-808f-e206398a9133"); + yield return new TestCaseData(DbType.Decimal, typeof(decimal), 342.23); + yield return new TestCaseData(DbType.Currency, typeof(decimal), 1233.3); + yield return new TestCaseData(DbType.Single, typeof(float), 20.34f); + yield return new TestCaseData(DbType.Double, typeof(double), 3423.234d); + yield return new TestCaseData(DbType.DateTime, typeof(DateTime), "2019-03-13 03:20:35.23 AM"); + yield return new TestCaseData(DbType.Date, typeof(DateTime), "2018-07-04 23:20:35.23 PM"); + yield return new TestCaseData(DbType.Time, typeof(DateTime), "2014-09-10 23:20:35"); }