mirror of
https://github.com/DapperLib/Dapper.git
synced 2026-10-18 22:31:08 +08:00
aecffecae1
* attempt NRT makeover - annotate NRTs on GridReader API - add protected access to some of the GridReader internals - switch GridReader callbacks to be more type-independent docs lib updates; deal with yellow warnings and test failures (SQL server certs and cancellation surfacing differently) fix break simplify proposed GridReader changes to protected OnBeforeGrid and OnAfterGrid[Async] Builds: Bump library versions (#1935) Tests: Upgrade dependencies for Dependabot (#1936) I'll do a pass at all of these later, but getting CVE versions out of the pipe. Resolving 4 alerts here: https://github.com/DapperLib/Dapper/security/dependabot merge and lib updates allow Identity to be constructed on-the-fly inside GridReader fix build warnings include readme rev minor - enable [SkipLocalsInit] everywhere - use NET5_0_OR_GREATER for remoting check # Conflicts: # Dapper/CommandDefinition.cs # Dapper/DefaultTypeMap.cs # Dapper/SqlMapper.Async.cs # Dapper/SqlMapper.IDataReader.cs # Dapper/SqlMapper.Link.cs # Dapper/SqlMapper.cs # Directory.Build.props * shipped, not unshipped * fixup SqlBuilder; use is null / is not null * use central package management (#1949) * Nullable test tweaks * Nuget: let's just remove it! * 2 test fixes from review * fix FindExplicitConstructor * add GetPropertySetterOrThrow * fix NRT on FindConstructor * DapperRow: value is object? * use NotNullWhen * make constructor problem more obvious * test fixes --------- Co-authored-by: Nick Craver <nrcraver@gmail.com>
323 lines
13 KiB
C#
323 lines
13 KiB
C#
using System.Collections.Generic;
|
|
using System.Data.Common;
|
|
using System.Linq;
|
|
using Xunit;
|
|
|
|
namespace Dapper.Tests
|
|
{
|
|
[Collection("DataReaderTests")]
|
|
public sealed class SystemSqlClientDataReaderTests : DataReaderTests<SystemSqlClientProvider> { }
|
|
#if MSSQLCLIENT
|
|
[Collection("DataReaderTests")]
|
|
public sealed class MicrosoftSqlClientDataReaderTests : DataReaderTests<MicrosoftSqlClientProvider> { }
|
|
#endif
|
|
|
|
public abstract class DataReaderTests<TProvider> : TestBase<TProvider> where TProvider : DatabaseProvider
|
|
{
|
|
[Fact]
|
|
public void GetSameReaderForSameShape_IDataReader()
|
|
{
|
|
var origReader = connection.ExecuteReader("select 'abc' as Name, 123 as Id");
|
|
#pragma warning disable CS0618 // Type or member is obsolete
|
|
var origParser = origReader.GetRowParser(typeof(HazNameId));
|
|
|
|
var typedParser = origReader.GetRowParser<HazNameId>();
|
|
#pragma warning restore CS0618 // Type or member is obsolete
|
|
|
|
// because wrapped for IDataReader, not same instance each time
|
|
Assert.False(ReferenceEquals(origParser, typedParser));
|
|
|
|
var list = origReader.Parse<HazNameId>().ToList();
|
|
Assert.Single(list);
|
|
Assert.Equal("abc", list[0].Name);
|
|
Assert.Equal(123, list[0].Id);
|
|
origReader.Dispose();
|
|
|
|
var secondReader = connection.ExecuteReader("select 'abc' as Name, 123 as Id");
|
|
#pragma warning disable CS0618 // Type or member is obsolete
|
|
var secondParser = secondReader.GetRowParser(typeof(HazNameId));
|
|
var thirdParser = secondReader.GetRowParser(typeof(HazNameId), 1);
|
|
#pragma warning restore CS0618 // Type or member is obsolete
|
|
|
|
list = secondReader.Parse<HazNameId>().ToList();
|
|
Assert.Single(list);
|
|
Assert.Equal("abc", list[0].Name);
|
|
Assert.Equal(123, list[0].Id);
|
|
secondReader.Dispose();
|
|
|
|
// now: should be different readers, and because wrapped for IDataReader, not same parser
|
|
Assert.False(ReferenceEquals(origReader, secondReader));
|
|
Assert.False(ReferenceEquals(origParser, secondParser));
|
|
Assert.False(ReferenceEquals(secondParser, thirdParser));
|
|
}
|
|
|
|
[Fact]
|
|
public void GetSameReaderForSameShape_DbDataReader()
|
|
{
|
|
var origReader = Assert.IsAssignableFrom<DbDataReader>(connection.ExecuteReader("select 'abc' as Name, 123 as Id"));
|
|
var origParser = origReader.GetRowParser(typeof(HazNameId));
|
|
|
|
var typedParser = origReader.GetRowParser<HazNameId>();
|
|
|
|
Assert.True(ReferenceEquals(origParser, typedParser));
|
|
|
|
var list = origReader.Parse<HazNameId>().ToList();
|
|
Assert.Single(list);
|
|
Assert.Equal("abc", list[0].Name);
|
|
Assert.Equal(123, list[0].Id);
|
|
origReader.Dispose();
|
|
|
|
var secondReader = Assert.IsAssignableFrom<DbDataReader>(connection.ExecuteReader("select 'abc' as Name, 123 as Id"));
|
|
var secondParser = secondReader.GetRowParser(typeof(HazNameId));
|
|
var thirdParser = secondReader.GetRowParser(typeof(HazNameId), 1);
|
|
|
|
list = secondReader.Parse<HazNameId>().ToList();
|
|
Assert.Single(list);
|
|
Assert.Equal("abc", list[0].Name);
|
|
Assert.Equal(123, list[0].Id);
|
|
secondReader.Dispose();
|
|
|
|
// now: should be different readers, but same parser
|
|
Assert.False(ReferenceEquals(origReader, secondReader));
|
|
Assert.True(ReferenceEquals(origParser, secondParser));
|
|
Assert.False(ReferenceEquals(secondParser, thirdParser));
|
|
}
|
|
|
|
[Fact]
|
|
public void TestTreatIntAsABool()
|
|
{
|
|
// Test we are consistent with direct call to database, see TypeHandlerTests.TestTreatIntAsABool
|
|
using(var reader = connection.ExecuteReader("select CAST(1 AS BIT)"))
|
|
Assert.True(SqlMapper.Parse<bool>(reader).Single());
|
|
using (var reader = connection.ExecuteReader("select 1"))
|
|
Assert.True(SqlMapper.Parse<bool>(reader).Single());
|
|
}
|
|
|
|
[Fact]
|
|
public void DiscriminatedUnion_IDataReader()
|
|
{
|
|
var result = new List<Discriminated_BaseType>();
|
|
using (var reader = connection.ExecuteReader(@"
|
|
select 'abc' as Name, 1 as Type, 3.0 as Value
|
|
union all
|
|
select 'def' as Name, 2 as Type, 4.0 as Value"))
|
|
{
|
|
if (reader.Read())
|
|
{
|
|
#pragma warning disable CS0618
|
|
var toFoo = reader.GetRowParser<Discriminated_BaseType>(typeof(Discriminated_Foo));
|
|
var toBar = reader.GetRowParser<Discriminated_BaseType>(typeof(Discriminated_Bar));
|
|
#pragma warning restore CS0618
|
|
|
|
var col = reader.GetOrdinal("Type");
|
|
do
|
|
{
|
|
switch (reader.GetInt32(col))
|
|
{
|
|
case 1:
|
|
result.Add(toFoo(reader));
|
|
break;
|
|
case 2:
|
|
result.Add(toBar(reader));
|
|
break;
|
|
}
|
|
} while (reader.Read());
|
|
}
|
|
}
|
|
|
|
Assert.Equal(2, result.Count);
|
|
Assert.Equal(1, result[0].Type);
|
|
Assert.Equal(2, result[1].Type);
|
|
var foo = (Discriminated_Foo)result[0];
|
|
Assert.Equal("abc", foo.Name);
|
|
var bar = (Discriminated_Bar)result[1];
|
|
Assert.Equal((float)4.0, bar.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void DiscriminatedUnion_DbDataReader()
|
|
{
|
|
var result = new List<Discriminated_BaseType>();
|
|
using (var reader = Assert.IsAssignableFrom<DbDataReader>(connection.ExecuteReader(@"
|
|
select 'abc' as Name, 1 as Type, 3.0 as Value
|
|
union all
|
|
select 'def' as Name, 2 as Type, 4.0 as Value")))
|
|
{
|
|
if (reader.Read())
|
|
{
|
|
var toFoo = reader.GetRowParser<Discriminated_BaseType>(typeof(Discriminated_Foo));
|
|
var toBar = reader.GetRowParser<Discriminated_BaseType>(typeof(Discriminated_Bar));
|
|
|
|
var col = reader.GetOrdinal("Type");
|
|
do
|
|
{
|
|
switch (reader.GetInt32(col))
|
|
{
|
|
case 1:
|
|
result.Add(toFoo(reader));
|
|
break;
|
|
case 2:
|
|
result.Add(toBar(reader));
|
|
break;
|
|
}
|
|
} while (reader.Read());
|
|
}
|
|
}
|
|
|
|
Assert.Equal(2, result.Count);
|
|
Assert.Equal(1, result[0].Type);
|
|
Assert.Equal(2, result[1].Type);
|
|
var foo = (Discriminated_Foo)result[0];
|
|
Assert.Equal("abc", foo.Name);
|
|
var bar = (Discriminated_Bar)result[1];
|
|
Assert.Equal((float)4.0, bar.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void DiscriminatedUnionWithMultiMapping_IDataReader()
|
|
{
|
|
var result = new List<DiscriminatedWithMultiMapping_BaseType>();
|
|
using (var reader = connection.ExecuteReader(@"
|
|
select 'abc' as Name, 1 as Type, 3.0 as Value, 1 as Id, 'zxc' as Name
|
|
union all
|
|
select 'def' as Name, 2 as Type, 4.0 as Value, 2 as Id, 'qwe' as Name"))
|
|
{
|
|
if (reader.Read())
|
|
{
|
|
var col = reader.GetOrdinal("Type");
|
|
var splitOn = reader.GetOrdinal("Id");
|
|
|
|
#pragma warning disable CS0618
|
|
var toFoo = reader.GetRowParser<DiscriminatedWithMultiMapping_BaseType>(typeof(DiscriminatedWithMultiMapping_Foo), 0, splitOn);
|
|
var toBar = reader.GetRowParser<DiscriminatedWithMultiMapping_BaseType>(typeof(DiscriminatedWithMultiMapping_Bar), 0, splitOn);
|
|
var toHaz = reader.GetRowParser<HazNameId>(typeof(HazNameId), splitOn, reader.FieldCount - splitOn);
|
|
#pragma warning restore CS0618
|
|
|
|
do
|
|
{
|
|
DiscriminatedWithMultiMapping_BaseType? obj = null;
|
|
switch (reader.GetInt32(col))
|
|
{
|
|
case 1:
|
|
obj = toFoo(reader);
|
|
break;
|
|
case 2:
|
|
obj = toBar(reader);
|
|
break;
|
|
}
|
|
|
|
Assert.NotNull(obj);
|
|
obj!.HazNameIdObject = toHaz(reader);
|
|
result.Add(obj);
|
|
|
|
} while (reader.Read());
|
|
}
|
|
}
|
|
|
|
Assert.Equal(2, result.Count);
|
|
Assert.Equal(1, result[0].Type);
|
|
Assert.Equal(2, result[1].Type);
|
|
var foo = (DiscriminatedWithMultiMapping_Foo)result[0];
|
|
Assert.Equal("abc", foo.Name);
|
|
Assert.NotNull(foo.HazNameIdObject);
|
|
Assert.Equal(1, foo.HazNameIdObject.Id);
|
|
Assert.Equal("zxc", foo.HazNameIdObject!.Name);
|
|
var bar = (DiscriminatedWithMultiMapping_Bar)result[1];
|
|
Assert.Equal((float)4.0, bar.Value);
|
|
Assert.NotNull(bar.HazNameIdObject);
|
|
Assert.Equal(2, bar.HazNameIdObject.Id);
|
|
Assert.Equal("qwe", bar.HazNameIdObject.Name);
|
|
}
|
|
|
|
[Fact]
|
|
public void DiscriminatedUnionWithMultiMapping_DbDataReader()
|
|
{
|
|
var result = new List<DiscriminatedWithMultiMapping_BaseType>();
|
|
using (var reader = Assert.IsAssignableFrom<DbDataReader>(connection.ExecuteReader(@"
|
|
select 'abc' as Name, 1 as Type, 3.0 as Value, 1 as Id, 'zxc' as Name
|
|
union all
|
|
select 'def' as Name, 2 as Type, 4.0 as Value, 2 as Id, 'qwe' as Name")))
|
|
{
|
|
if (reader.Read())
|
|
{
|
|
var col = reader.GetOrdinal("Type");
|
|
var splitOn = reader.GetOrdinal("Id");
|
|
|
|
var toFoo = reader.GetRowParser<DiscriminatedWithMultiMapping_BaseType>(typeof(DiscriminatedWithMultiMapping_Foo), 0, splitOn);
|
|
var toBar = reader.GetRowParser<DiscriminatedWithMultiMapping_BaseType>(typeof(DiscriminatedWithMultiMapping_Bar), 0, splitOn);
|
|
var toHaz = reader.GetRowParser<HazNameId>(typeof(HazNameId), splitOn, reader.FieldCount - splitOn);
|
|
|
|
do
|
|
{
|
|
DiscriminatedWithMultiMapping_BaseType? obj = null;
|
|
switch (reader.GetInt32(col))
|
|
{
|
|
case 1:
|
|
obj = toFoo(reader);
|
|
break;
|
|
case 2:
|
|
obj = toBar(reader);
|
|
break;
|
|
}
|
|
|
|
Assert.NotNull(obj);
|
|
obj.HazNameIdObject = toHaz(reader);
|
|
result.Add(obj);
|
|
|
|
} while (reader.Read());
|
|
}
|
|
}
|
|
|
|
Assert.Equal(2, result.Count);
|
|
Assert.Equal(1, result[0].Type);
|
|
Assert.Equal(2, result[1].Type);
|
|
var foo = (DiscriminatedWithMultiMapping_Foo)result[0];
|
|
Assert.Equal("abc", foo.Name);
|
|
Assert.NotNull(foo.HazNameIdObject);
|
|
Assert.Equal(1, foo.HazNameIdObject.Id);
|
|
Assert.Equal("zxc", foo.HazNameIdObject.Name);
|
|
var bar = (DiscriminatedWithMultiMapping_Bar)result[1];
|
|
Assert.Equal((float)4.0, bar.Value);
|
|
Assert.NotNull(bar.HazNameIdObject);
|
|
Assert.Equal(2, bar.HazNameIdObject.Id);
|
|
Assert.Equal("qwe", bar.HazNameIdObject.Name);
|
|
}
|
|
|
|
private abstract class Discriminated_BaseType
|
|
{
|
|
public abstract int Type { get; }
|
|
}
|
|
|
|
private class Discriminated_Foo : Discriminated_BaseType
|
|
{
|
|
public string? Name { get; set; }
|
|
public override int Type => 1;
|
|
}
|
|
|
|
private class Discriminated_Bar : Discriminated_BaseType
|
|
{
|
|
public float Value { get; set; }
|
|
public override int Type => 2;
|
|
}
|
|
|
|
private abstract class DiscriminatedWithMultiMapping_BaseType : Discriminated_BaseType
|
|
{
|
|
public abstract HazNameId? HazNameIdObject { get; set; }
|
|
}
|
|
|
|
private class DiscriminatedWithMultiMapping_Foo : DiscriminatedWithMultiMapping_BaseType
|
|
{
|
|
public override HazNameId? HazNameIdObject { get; set; }
|
|
public string? Name { get; set; }
|
|
public override int Type => 1;
|
|
}
|
|
|
|
private class DiscriminatedWithMultiMapping_Bar : DiscriminatedWithMultiMapping_BaseType
|
|
{
|
|
public override HazNameId? HazNameIdObject { get; set; }
|
|
public float Value { get; set; }
|
|
public override int Type => 2;
|
|
}
|
|
}
|
|
}
|