Skip to content

Commit

Permalink
This simple Guid handler should fix issue DapperLib#447 (and duplicat…
Browse files Browse the repository at this point in the history
…e issue: DapperLib#718). It implements the method suggested by numerous other users but leaves the byte order (endian) to the .net layer.

It also fixes the guid equivalent issue raised in DapperLib#461.
  • Loading branch information
Chris McCauley committed Jul 25, 2018
1 parent e7ba305 commit 3b001ca
Show file tree
Hide file tree
Showing 6 changed files with 259 additions and 0 deletions.
40 changes: 40 additions & 0 deletions Dapper.Tests.SQlite/ClassWithGuidPropertyWithDefaultConstructor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;

namespace Dapper.Tests.SQlite
{
/// <summary>
/// ClassWithGuidPropertyWithDefaultConstructor: simple class with a Guid property and a default constructor.
/// </summary>
public class ClassWithGuidPropertyWithDefaultConstructor : IEquatable<ClassWithGuidPropertyWithDefaultConstructor>
{
/// <summary>
/// Id: is the GUID id for "this" record.
/// </summary>
public Guid Id { get; set; }

/// <summary>
/// Name: is an arbitary (null-guid) dummy property
/// </summary>
public string Name { get; set; }

/// <inheritdoc cref="ClassWithGuidPropertyWithDefaultConstructor " />
public bool Equals(ClassWithGuidPropertyWithDefaultConstructor x, ClassWithGuidPropertyWithDefaultConstructor y)
{
return x.Id.Equals(y.Id) && x.Name.Equals(y.Name);
}

/// <summary>
///
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
public bool Equals(ClassWithGuidPropertyWithDefaultConstructor other)
{
return Id.Equals(other.Id) && Name.Equals(other.Name);
}

/// <inheritdoc cref="ClassWithGuidPropertyWithDefaultConstructor" />
public int GetHashCode(ClassWithGuidPropertyWithDefaultConstructor obj) => throw new NotImplementedException();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;

namespace Dapper.Tests.SQlite
{
/// <summary>
/// ClassWithGuidPropertyWithNoDefaultConstructor: simple class with a Guid property and no default constructor.
/// </summary>
public class ClassWithGuidPropertyWithNoDefaultConstructor : IEquatable<ClassWithGuidPropertyWithNoDefaultConstructor>
{
/// <summary>
/// Id: is the GUID id for "this" record.
/// </summary>
public Guid Id { get; set; }

/// <summary>
/// Name: is an arbitary (null-guid) dummy property
/// </summary>
public string Name { get; set; }

public ClassWithGuidPropertyWithNoDefaultConstructor(Guid id, string name)
{
Id = id;
Name = name;
}

/// <inheritdoc cref="ClassWithGuidPropertyWithNoDefaultConstructor" />
public bool Equals(ClassWithGuidPropertyWithNoDefaultConstructor x, ClassWithGuidPropertyWithNoDefaultConstructor y)
{
return x.Id.Equals(y.Id) && x.Name.Equals(y.Name);
}

/// <summary>
///
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
public bool Equals(ClassWithGuidPropertyWithNoDefaultConstructor other)
{
return Id.Equals(other.Id) && Name.Equals(other.Name);
}

/// <inheritdoc cref="ClassWithGuidPropertyWithNoDefaultConstructor" />
public int GetHashCode(ClassWithGuidPropertyWithNoDefaultConstructor obj) => throw new NotImplementedException();
}

}
29 changes: 29 additions & 0 deletions Dapper.Tests.SQlite/Dapper.Tests.SQlite.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>

<IsPackable>false</IsPackable>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<NoWarn>1701;1702;1591</NoWarn>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp2.1'">
<PackageReference Include="Microsoft.Data.Sqlite" Version="2.1.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Dapper\Dapper.csproj" />
</ItemGroup>


</Project>
33 changes: 33 additions & 0 deletions Dapper.Tests.SQlite/GuidHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Text;

namespace Dapper.Tests.SQlite
{
/// <summary>
///
/// </summary>
public class GuidHandler : SqlMapper.TypeHandler<Guid>
{
/// <summary>
///
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public override Guid Parse(object value)
{
return new Guid((byte[])value);
}

/// <summary>
///
/// </summary>
/// <param name="parameter"></param>
/// <param name="value"></param>
public override void SetValue(IDbDataParameter parameter, Guid value)
{
parameter.Value = value.ToByteArray();
}
}
}
104 changes: 104 additions & 0 deletions Dapper.Tests.SQlite/TestGuidPropertyIssue.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using System;
using System.Linq;
using Microsoft.Data.Sqlite;
using Xunit;

namespace Dapper.Tests.SQlite
{

/// <summary>
/// Test the handling of classes with guid type properties and persisting them to a sqlite database.
/// </summary>
public class TestGuidPropertyIssue
{
private const string TEST_STRING = "Test Name";
private const string CREATE_STATEMENT = @"CREATE TABLE IF NOT EXISTS SomeTable (Id UNIQUEIDENTIFIER, Name NVARCHAR(255))";
private const string INSERT_STATEMENT = @"INSERT INTO SomeTable (Id, Name) VALUES(@Id, @Name)";
private const string SELECT_STATEMENT = @"SELECT * FROM SomeTable";

private static SqliteConnection GetSQLiteConnection(bool open = true)
{
var connection = new SqliteConnection("Data Source=:memory:");
if (open) connection.Open();
return connection;
}

public TestGuidPropertyIssue()
{
// Add the new Guid handler for all the tests.
SqlMapper.AddTypeHandler(new GuidHandler());
}

[Fact]
public void Test_select_of_class_with_guid_property_and_default_constructor()
{
using (var connection = GetSQLiteConnection())
{
// Arrange.
var seed = Guid.NewGuid();

var expectedRes = new ClassWithGuidPropertyWithDefaultConstructor()
{
Id = seed,
Name = TEST_STRING
};

connection.Execute(CREATE_STATEMENT);
connection.Execute(INSERT_STATEMENT, expectedRes);

// Act.
var res = connection.Query<ClassWithGuidPropertyWithDefaultConstructor>(SELECT_STATEMENT).FirstOrDefault();

// Assert.
Assert.Equal(expectedRes, res);
}
}

[Fact]
public void Test_select_of_class_with_guid_property_and_no_default_constructor()
{
using (var connection = GetSQLiteConnection())
{
// Arrange.
var seed = Guid.NewGuid();

var expectedRes = new ClassWithGuidPropertyWithNoDefaultConstructor( seed, TEST_STRING);

connection.Execute(CREATE_STATEMENT);
connection.Execute(INSERT_STATEMENT, expectedRes);

// Act.
var res = connection.Query<ClassWithGuidPropertyWithNoDefaultConstructor>(SELECT_STATEMENT).FirstOrDefault();

// Assert.
Assert.Equal(expectedRes, res);
}
}

[Fact]
public void Test_Insert_Using_Anonymous_Object()
{
using (var connection = GetSQLiteConnection())
{
// Arrange.
var seed = Guid.NewGuid();

var expectedRes = new ClassWithGuidPropertyWithNoDefaultConstructor(seed, TEST_STRING);

connection.Execute(CREATE_STATEMENT);
connection.Execute(INSERT_STATEMENT, new
{
Id = seed,
Name = "Test Name"
});

// Act.
var res = connection.Query<ClassWithGuidPropertyWithNoDefaultConstructor>(SELECT_STATEMENT).FirstOrDefault();

// Assert.
Assert.Equal(expectedRes, res);
}
}

}
}
7 changes: 7 additions & 0 deletions Dapper.sln
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.EntityFramework.Stro
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.Tests.Performance", "Dapper.Tests.Performance\Dapper.Tests.Performance.csproj", "{F017075A-2969-4A8E-8971-26F154EB420F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.Tests.SQlite", "Dapper.Tests.SQlite\Dapper.Tests.SQlite.csproj", "{AEFAC4E2-5B64-42FA-B9DA-6FDBE9C6066E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -88,6 +90,10 @@ Global
{F017075A-2969-4A8E-8971-26F154EB420F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F017075A-2969-4A8E-8971-26F154EB420F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F017075A-2969-4A8E-8971-26F154EB420F}.Release|Any CPU.Build.0 = Release|Any CPU
{AEFAC4E2-5B64-42FA-B9DA-6FDBE9C6066E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AEFAC4E2-5B64-42FA-B9DA-6FDBE9C6066E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AEFAC4E2-5B64-42FA-B9DA-6FDBE9C6066E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AEFAC4E2-5B64-42FA-B9DA-6FDBE9C6066E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -103,6 +109,7 @@ Global
{8A74F0B6-188F-45D2-8A4B-51E4F211805A} = {4E956F6B-6BD8-46F5-BC85-49292FF8F9AB}
{39D3EEB6-9C05-4F4A-8C01-7B209742A7EB} = {4E956F6B-6BD8-46F5-BC85-49292FF8F9AB}
{F017075A-2969-4A8E-8971-26F154EB420F} = {568BD46C-1C65-4D44-870C-12CD72563262}
{AEFAC4E2-5B64-42FA-B9DA-6FDBE9C6066E} = {568BD46C-1C65-4D44-870C-12CD72563262}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {928A4226-96F3-409A-8A83-9E7444488710}
Expand Down

0 comments on commit 3b001ca

Please sign in to comment.