diff --git a/CodeOnlyStoredProcedure/StoredProcedureExtensions.WithParameter.cs b/CodeOnlyStoredProcedure/StoredProcedureExtensions.WithParameter.cs index 0260a4f..78c934f 100644 --- a/CodeOnlyStoredProcedure/StoredProcedureExtensions.WithParameter.cs +++ b/CodeOnlyStoredProcedure/StoredProcedureExtensions.WithParameter.cs @@ -28,7 +28,7 @@ public static TSP WithParameter(this TSP sp, string name, TValue va Contract.Requires(!string.IsNullOrWhiteSpace(name)); Contract.Ensures(Contract.Result() != null); - return (TSP)sp.CloneWith(new InputParameter(name, value)); + return (TSP)sp.CloneWith(new InputParameter(name, value, typeof(TValue).InferDbType())); } /// diff --git a/CodeOnlyStoredProcedure/StoredProcedureParameters/InputOutputParameter.cs b/CodeOnlyStoredProcedure/StoredProcedureParameters/InputOutputParameter.cs index 0d6d830..ae87ebb 100644 --- a/CodeOnlyStoredProcedure/StoredProcedureParameters/InputOutputParameter.cs +++ b/CodeOnlyStoredProcedure/StoredProcedureParameters/InputOutputParameter.cs @@ -53,7 +53,7 @@ public void TransferOutputValue(object value) public override string ToString() { - return string.Format("[InOut] @{0} = '{1}'", ParameterName, Value ?? "{null}"); + return string.Format("[InOut] @{0} = '{1}'", ParameterName.StartsWith("@") ? ParameterName.Substring(1) : ParameterName, Value ?? "{null}"); } } } diff --git a/CodeOnlyStoredProcedure/StoredProcedureParameters/InputParameter.cs b/CodeOnlyStoredProcedure/StoredProcedureParameters/InputParameter.cs index e2eef6f..41c031d 100644 --- a/CodeOnlyStoredProcedure/StoredProcedureParameters/InputParameter.cs +++ b/CodeOnlyStoredProcedure/StoredProcedureParameters/InputParameter.cs @@ -29,7 +29,7 @@ public IDbDataParameter CreateDbDataParameter(IDbCommand command) public override string ToString() { - return string.Format("@{0} = '{1}'", ParameterName, Value ?? "{null}"); + return string.Format("@{0} = '{1}'", ParameterName.StartsWith("@") ? ParameterName.Substring(1) : ParameterName, Value ?? "{null}"); } private DbType GetDbType() diff --git a/CodeOnlyStoredProcedure/StoredProcedureParameters/OutputParameter.cs b/CodeOnlyStoredProcedure/StoredProcedureParameters/OutputParameter.cs index 895f051..512dd61 100644 --- a/CodeOnlyStoredProcedure/StoredProcedureParameters/OutputParameter.cs +++ b/CodeOnlyStoredProcedure/StoredProcedureParameters/OutputParameter.cs @@ -48,7 +48,7 @@ public void TransferOutputValue(object value) public override string ToString() { - return string.Format("[Out] @{0}", ParameterName); + return string.Format("[Out] @{0}", ParameterName.StartsWith("@") ? ParameterName.Substring(1) : ParameterName); } } } diff --git a/CodeOnlyStoredProcedure/StoredProcedureParameters/TableValuedParameter.cs b/CodeOnlyStoredProcedure/StoredProcedureParameters/TableValuedParameter.cs index 12e89e3..051b3a3 100644 --- a/CodeOnlyStoredProcedure/StoredProcedureParameters/TableValuedParameter.cs +++ b/CodeOnlyStoredProcedure/StoredProcedureParameters/TableValuedParameter.cs @@ -49,7 +49,7 @@ public IDbDataParameter CreateDbDataParameter(IDbCommand command) public override string ToString() { - return string.Format("@{0} = IEnumerable<{1}> ({2} items)", ParameterName, valueType, GetValueCount()); + return string.Format("@{0} = IEnumerable<{1}> ({2} items)", ParameterName.StartsWith("@") ? ParameterName.Substring(1) : ParameterName, valueType, GetValueCount()); } private int GetValueCount() diff --git a/CodeOnlyStoredProcedures.nuspec b/CodeOnlyStoredProcedures.nuspec index efa55ad..90c585a 100644 --- a/CodeOnlyStoredProcedures.nuspec +++ b/CodeOnlyStoredProcedures.nuspec @@ -9,7 +9,11 @@ false A library for easily calling Stored Procedures in .NET. Works great with Entity Framework Code First models. Code Only Stored Procedures will not create any Stored Procedures on your database. Instead, its aim is to make it easy to call your existing stored procedures by writing simple code. - 2.2.3 + 2.2.4 +Fixed bug where calling ToString on a stored procedure could print parameters with a double @. +Fixed bug where the fluent syntax would not infer the type of its parameters from the compile time generic parameter type. + +2.2.3 Fixed bug where dynamic stored procedures wouldn't close their connections. 2.2.2 @@ -53,11 +57,7 @@ Added ability to specify an implementation of an interface, so a StoredProcedure Added better exception when a model is missing a public parameterless constructor. 1.2.0 -Added a much cleaner syntax for calling stored procedures, by using dynamic objects. - -1.1.0 -Improved exceptions so that it is easier to determine why the data returned doesn't map to your model correctly. -Now ignores read-only properties, so they don't have to be attributed with [NotMapped] +Added a much cleaner syntax for calling stored procedures, by using dynamic objects. StoredProcedure EntityFramework EF diff --git a/CodeOnlyTests-NET40/CodeOnlyTests-NET40.csproj b/CodeOnlyTests-NET40/CodeOnlyTests-NET40.csproj index f71b95d..9c1e37d 100644 --- a/CodeOnlyTests-NET40/CodeOnlyTests-NET40.csproj +++ b/CodeOnlyTests-NET40/CodeOnlyTests-NET40.csproj @@ -46,12 +46,12 @@ False ..\packages\EntityFramework.6.1.3\lib\net40\EntityFramework.SqlServer.dll - - ..\packages\FluentAssertions.3.5.0\lib\net40\FluentAssertions.dll + + ..\packages\FluentAssertions.4.1.0\lib\net40\FluentAssertions.dll True - - ..\packages\FluentAssertions.3.5.0\lib\net40\FluentAssertions.Core.dll + + ..\packages\FluentAssertions.4.1.0\lib\net40\FluentAssertions.Core.dll True @@ -64,8 +64,8 @@ ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll - - ..\packages\Moq.4.2.1507.0118\lib\net40\Moq.dll + + ..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll True diff --git a/CodeOnlyTests-NET40/packages.config b/CodeOnlyTests-NET40/packages.config index f9bf68f..774e39b 100644 --- a/CodeOnlyTests-NET40/packages.config +++ b/CodeOnlyTests-NET40/packages.config @@ -1,9 +1,9 @@  - + - + \ No newline at end of file diff --git a/CodeOnlyTests/CodeOnlyTests.csproj b/CodeOnlyTests/CodeOnlyTests.csproj index dff0c0c..aed11d5 100644 --- a/CodeOnlyTests/CodeOnlyTests.csproj +++ b/CodeOnlyTests/CodeOnlyTests.csproj @@ -37,17 +37,17 @@ 4 - - ..\packages\FluentAssertions.3.5.0\lib\net45\FluentAssertions.dll + + ..\packages\FluentAssertions.4.1.0\lib\net45\FluentAssertions.dll True - - ..\packages\FluentAssertions.3.5.0\lib\net45\FluentAssertions.Core.dll + + ..\packages\FluentAssertions.4.1.0\lib\net45\FluentAssertions.Core.dll True - - ..\packages\Moq.4.2.1507.0118\lib\net40\Moq.dll + + ..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll True diff --git a/CodeOnlyTests/StoredProcedureExtensionsTests.WithParameter.cs b/CodeOnlyTests/StoredProcedureExtensionsTests.WithParameter.cs index 0a9f947..70ab675 100644 --- a/CodeOnlyTests/StoredProcedureExtensionsTests.WithParameter.cs +++ b/CodeOnlyTests/StoredProcedureExtensionsTests.WithParameter.cs @@ -56,5 +56,20 @@ public void TestWithParameterClonesStoredProcedureWithResultType() var param = toTest.Parameters.Should().ContainSingle(p => p.ParameterName == "Foo", "because we added one Parameter").Which; param.Should().BeOfType().Which.Value.Should().Be("Bar", "because it was passed to WithInputParameter"); } + + [TestMethod] + public void TestWithParameter_InfersTheDbType() + { + var orig = new StoredProcedure("Test"); + + var toTest = orig.WithParameter("Foo", "Bar"); + + toTest.Should().NotBeSameAs(orig, "because StoredProcedures should be immutable"); + orig.Parameters.Should().BeEmpty("because StoredProcedures should be immutable"); + + var param = toTest.Parameters.Should().ContainSingle(p => p.ParameterName == "Foo", "because we added one Parameter").Which; + param.Should().BeOfType().Which.Value.Should().Be("Bar", "because it was passed to WithInputParameter"); + param.Should().BeOfType().Which.DbType.Should().Be(DbType.String, "because the DbType should be inferred if possible"); + } } } diff --git a/CodeOnlyTests/StoredProcedureParameters/InputOutputParameterTests.cs b/CodeOnlyTests/StoredProcedureParameters/InputOutputParameterTests.cs index fafd41b..e65013e 100644 --- a/CodeOnlyTests/StoredProcedureParameters/InputOutputParameterTests.cs +++ b/CodeOnlyTests/StoredProcedureParameters/InputOutputParameterTests.cs @@ -90,5 +90,11 @@ public void NullValueToStringReturnsCorrectString() { new InputOutputParameter("Foo", o => { }, null).ToString().Should().Be("[InOut] @Foo = '{null}'"); } + + [TestMethod] + public void ToStringDoesNotDisplayExtraAts() + { + new InputOutputParameter("@Foo", o => { }, "Bar").ToString().Should().Be("[InOut] @Foo = 'Bar'"); + } } } diff --git a/CodeOnlyTests/StoredProcedureParameters/InputParameterTests.cs b/CodeOnlyTests/StoredProcedureParameters/InputParameterTests.cs index ed62e80..6526991 100644 --- a/CodeOnlyTests/StoredProcedureParameters/InputParameterTests.cs +++ b/CodeOnlyTests/StoredProcedureParameters/InputParameterTests.cs @@ -76,5 +76,11 @@ public void NullValueToStringReturnsCorrectString() { new InputParameter("Foo", null).ToString().Should().Be("@Foo = '{null}'"); } + + [TestMethod] + public void ToStringDoesNotDisplayExtraAts() + { + new InputParameter("@Foo", "Bar").ToString().Should().Be("@Foo = 'Bar'"); + } } } diff --git a/CodeOnlyTests/StoredProcedureParameters/OutputParameterTests.cs b/CodeOnlyTests/StoredProcedureParameters/OutputParameterTests.cs index 28a7abf..7cd0660 100644 --- a/CodeOnlyTests/StoredProcedureParameters/OutputParameterTests.cs +++ b/CodeOnlyTests/StoredProcedureParameters/OutputParameterTests.cs @@ -44,5 +44,11 @@ public void ToStringRepresentsTheParameter() { new OutputParameter("Foo", o => { }).ToString().Should().Be("[Out] @Foo"); } + + [TestMethod] + public void ToStringDoesNotDisplayExtraAts() + { + new OutputParameter("@Foo", o => { }).ToString().Should().Be("[Out] @Foo"); + } } } diff --git a/CodeOnlyTests/StoredProcedureParameters/TableValuedParameterTests.cs b/CodeOnlyTests/StoredProcedureParameters/TableValuedParameterTests.cs index 8b545c5..272b143 100644 --- a/CodeOnlyTests/StoredProcedureParameters/TableValuedParameterTests.cs +++ b/CodeOnlyTests/StoredProcedureParameters/TableValuedParameterTests.cs @@ -83,6 +83,13 @@ public void ToStringRepresentsTheParameter() .Should().Be(string.Format("@Foo = IEnumerable<{0}> (1 items)", typeof(TVP))); } + [TestMethod] + public void ToStringDoesNotDisplayExtraAts() + { + new TableValuedParameter("@Foo", new[] { new TVP(42) }, typeof(TVP), "CustomInt", "Schema").ToString() + .Should().Be(string.Format("@Foo = IEnumerable<{0}> (1 items)", typeof(TVP))); + } + private class TVP { public int Int { get; set; } diff --git a/CodeOnlyTests/packages.config b/CodeOnlyTests/packages.config index 531aa8f..fcdfcad 100644 --- a/CodeOnlyTests/packages.config +++ b/CodeOnlyTests/packages.config @@ -1,5 +1,5 @@  - - + + \ No newline at end of file diff --git a/SmokeTests/DynamicSyntax.cs b/SmokeTests/DynamicSyntax.cs index c324363..1a1faa7 100644 --- a/SmokeTests/DynamicSyntax.cs +++ b/SmokeTests/DynamicSyntax.cs @@ -393,6 +393,37 @@ Tuple SingleColumnSingleRowTimeSpanSync(IDbConnection db) return Tuple.Create(true, ""); } + + // THIS DOESN'T WORK... Not sure if it can ever be enabled. Maybe if null parameters aren't actually passed to the sproc? + //[SmokeTest("Dynamic Syntax Single Column Single Row with nullable parameter")] + Tuple SingleColumnSingleRowTimeSpanSyncWithNullableParameter(IDbConnection db) + { + var d1 = DateTime.Now.AddHours(-1); + DateTime? d2 = null; + TimeSpan result = db.Execute(Program.timeout).usp_TimeDifference(date1: d1, date2: d2); + + if ((result - System.TimeSpan.FromHours(1)).Duration() > TimeSpan.FromSeconds(1)) + return Tuple.Create(false, string.Format("expected value at least {0}, but returned {1}", TimeSpan.FromHours(1), result)); + + return Tuple.Create(true, ""); + } + + [SmokeTest("Dynamic Syntax Single Column Single Row with nullable parameter via anonymous type")] + Tuple SingleColumnSingleRowTimeSpanSyncWithNullableParameterViaAnonymousType(IDbConnection db) + { + var d1 = DateTime.Now.AddHours(-1); + DateTime? d2 = null; + TimeSpan result = db.Execute(Program.timeout).usp_TimeDifference(new + { + date1 = d1, + date2 = d2 + }); + + if ((result - System.TimeSpan.FromHours(1)).Duration() > TimeSpan.FromSeconds(1)) + return Tuple.Create(false, string.Format("expected value at least {0}, but returned {1}", TimeSpan.FromHours(1), result)); + + return Tuple.Create(true, ""); + } [SmokeTest("Dynamic Syntax Single Column Single Row (Await)")] async Task> SingleColumnSingleRowTimeSpanAsync(IDbConnection db) diff --git a/SmokeTests/FluentSyntax.cs b/SmokeTests/FluentSyntax.cs index 5c371c6..3542e3d 100644 --- a/SmokeTests/FluentSyntax.cs +++ b/SmokeTests/FluentSyntax.cs @@ -796,6 +796,67 @@ Task> SingleColumnSingleRowUntypedTimeSpanTask(IDbConnection return Tuple.Create(true, ""); }); } + + [SmokeTest("Fluent Syntax Single Column Single Row with nullable parameter (Task)")] + Task> SingleColumnSingleRowTimeSpanTaskWithNullableParameter(IDbConnection db) + { + var d1 = DateTime.Now.AddHours(-1); + DateTime? d2 = null; + + var results = StoredProcedure.Create("usp_TimeDifference") + .WithParameter("date1", d1) + .WithParameter("date2", d2) + .WithResults() + .ExecuteAsync(db, Program.timeout); + + + return results.ContinueWith(r => + { + var res = r.Result.Single(); + if ((res - System.TimeSpan.FromHours(1)).Duration() > TimeSpan.FromSeconds(1)) + return Tuple.Create(false, string.Format("expected {0}, but returned {1}", TimeSpan.FromHours(1), res)); + + return Tuple.Create(true, ""); + }); + } + + [SmokeTest("Fluent Syntax Single Column Single Row with nullable parameter (Await)")] + async Task> SingleColumnSingleRowTimeSpanASyncWithNullableParameter(IDbConnection db) + { + var d1 = DateTime.Now.AddHours(-1); + DateTime? d2 = null; + + var results = await StoredProcedure.Create("usp_TimeDifference") + .WithParameter("date1", d1) + .WithParameter("date2", d2) + .WithResults() + .ExecuteAsync(db, Program.timeout); + + var res = results.Single(); + if ((res - System.TimeSpan.FromHours(1)).Duration() > TimeSpan.FromSeconds(1)) + return Tuple.Create(false, string.Format("expected {0}, but returned {1}", TimeSpan.FromHours(1), res)); + + return Tuple.Create(true, ""); + } + + [SmokeTest("Fluent Syntax Single Column Single Row with nullable parameter (Await)")] + Tuple SingleColumnSingleRowTimeSpanSyncWithNullableParameter(IDbConnection db) + { + var d1 = DateTime.Now.AddHours(-1); + DateTime? d2 = null; + + var results = StoredProcedure.Create("usp_TimeDifference") + .WithParameter("date1", d1) + .WithParameter("date2", d2) + .WithResults() + .Execute(db, Program.timeout); + + var res = results.Single(); + if ((res - System.TimeSpan.FromHours(1)).Duration() > TimeSpan.FromSeconds(1)) + return Tuple.Create(false, string.Format("expected {0}, but returned {1}", TimeSpan.FromHours(1), res)); + + return Tuple.Create(true, ""); + } private class TimespanResult { diff --git a/SmokeTests/Smoke.mdf b/SmokeTests/Smoke.mdf index 7abeb0e..da8749c 100644 Binary files a/SmokeTests/Smoke.mdf and b/SmokeTests/Smoke.mdf differ diff --git a/SmokeTests/Smoke_log.ldf b/SmokeTests/Smoke_log.ldf index d7bce26..41f655e 100644 Binary files a/SmokeTests/Smoke_log.ldf and b/SmokeTests/Smoke_log.ldf differ diff --git a/appveyor.yml b/appveyor.yml index fae2290..fddb42f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,14 +1,17 @@ -version: 2.2.3.{build} +version: 2.2.4.{build} skip_tags: false +# Operating system (build VM template) +os: Visual Studio 2013 + branches: # blacklist gh-pages, since the documentation branch shouldn't be built except: - gh-pages environment: - releaseVersion: 2.2.3 - packageVersion: 2.2.3 + releaseVersion: 2.2.4 + packageVersion: 2.2.4-pre assembly_info: patch: true