Skip to content

Commit

Permalink
Fixed issue causing explicit null FK's in insert statement to be ignored
Browse files Browse the repository at this point in the history
  • Loading branch information
carl-berg committed Feb 3, 2021
1 parent fc1b174 commit 2c9c9eb
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 23 deletions.
7 changes: 7 additions & 0 deletions DataDude.Tests/Core/Scripts/Migrations/1.0.0/01.Schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ CREATE TABLE Test_PK_Sequential_Uuid(
)
GO

CREATE TABLE Test_Nullable_FK(
Id INT PRIMARY KEY,
OfficeId INT NULL,
CONSTRAINT FK_Test_Nullable_FK_Office FOREIGN KEY (OfficeId) references Buildings.Office(Id),
)
GO

CREATE TRIGGER People.EmployeeUpdatedAt ON People.Employee AFTER UPDATE AS BEGIN
UPDATE People.Employee
SET People.Employee.UpdatedAt = GETDATE()
Expand Down
18 changes: 18 additions & 0 deletions DataDude.Tests/Inserts/InstructionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -255,5 +255,23 @@ public async Task Can_Insert_Sequential_Default_Using_Generated_Value_Instead_Of
var rows = await connection.QueryFirstAsync<int>("SELECT Count(1) FROM Test_PK_Sequential_Uuid");
rows.ShouldBe(1);
}

[Fact]
public async Task Can_Honor_Specified_Null_Values_When_Inserting_Nullable_FK()
{
using var connection = Fixture.CreateNewConnection();

await new Dude()
.EnableAutomaticForeignKeys()
.Insert("Office", new { Id = 1 })
.Insert("Test_Nullable_FK", new { Id = 1 })
.Insert("Test_Nullable_FK", new { Id = 2, OfficeId = (int?)null })
.Go(connection);

var firstOfficeId = await connection.QuerySingleAsync<int?>("SELECT OfficeId FROM Test_Nullable_FK WHERE Id = 1");
var secondOfficeId = await connection.QuerySingleAsync<int?>("SELECT OfficeId FROM Test_Nullable_FK WHERE Id = 2");
firstOfficeId.ShouldBe(1);
secondOfficeId.ShouldBeNull();
}
}
}
34 changes: 33 additions & 1 deletion DataDude/DataDudeContext.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Data;
using System.Threading.Tasks;
using DataDude.Instructions;
Expand All @@ -24,6 +25,27 @@ public DataDudeContext(ISchemaLoader schemaLoader)
InstructionPreProcessors = new List<IInstructionPreProcessor>();
}

public static IDictionary<string, DbType> TypeMappings { get; } = new Dictionary<string, DbType>
{
["bit"] = DbType.Boolean,
["date"] = DbType.Date,
["datetime"] = DbType.DateTime,
["datetime2"] = DbType.DateTime2,
["datetimeoffset"] = DbType.DateTimeOffset,
["decimal"] = DbType.Decimal,
["numeric"] = DbType.Decimal,
["float"] = DbType.Double,
["uniqueidentifier"] = DbType.Guid,
["smallint"] = DbType.Int16,
["int"] = DbType.Int32,
["bigint"] = DbType.Int64,
["variant"] = DbType.Object,
["varbinary"] = DbType.Binary,
["varchar"] = DbType.String,
["nvarchar"] = DbType.String,
["geography"] = DbType.String,
};

public ISchemaLoader SchemaLoader { get; }

public IList<IInstruction> Instructions { get; }
Expand All @@ -34,6 +56,16 @@ public DataDudeContext(ISchemaLoader schemaLoader)

public SchemaInformation? Schema { get; private set; }

public static DbType GetDbType(ColumnInformation column)
{
if (TypeMappings.ContainsKey(column.DataType))
{
return TypeMappings[column.DataType];
}

throw new NotImplementedException($"Db type for {column.DataType} of column {column.Table.FullName}.{column.Name} is not known");
}

public T? Get<T>(string key)
{
if (_store.TryGetValue(key, out var value) && value is T typedValue)
Expand Down
11 changes: 9 additions & 2 deletions DataDude/Instructions/Insert/InsertData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,16 @@ public InsertData(TableInformation table, InsertInstruction instruction)

foreach (var column in table)
{
if (instruction.ColumnValues.TryGetValue(column.Name, out var value) && value is { })
if (instruction.ColumnValues.ContainsKey(column.Name))
{
_data.Add(column, new ColumnValue(value));
if (instruction.ColumnValues[column.Name] is { } value)
{
_data.Add(column, new ColumnValue(value));
}
else
{
_data.Add(column, ColumnValue.Null(DataDudeContext.GetDbType(column)));
}
}
else
{
Expand Down
21 changes: 1 addition & 20 deletions DataDude/Instructions/Insert/ValueProviders/ValueProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public void Process(ColumnInformation column, ColumnValue value)
}
else if (column.IsNullable)
{
value.Set(ColumnValue.Null(GetNullDbType(column.DataType)));
value.Set(ColumnValue.Null(DataDudeContext.GetDbType(column)));
}
else if (GetDefaultValue(column, value) is { } newValue)
{
Expand All @@ -29,24 +29,5 @@ public void Process(ColumnInformation column, ColumnValue value)
}

protected abstract ColumnValue? GetDefaultValue(ColumnInformation column, ColumnValue value);

private DbType GetNullDbType(string dataType) => dataType switch
{
"bit" => DbType.Boolean,
"date" => DbType.Date,
"datetime" => DbType.DateTime,
"datetime2" => DbType.DateTime2,
"datetimeoffset" => DbType.DateTimeOffset,
"decimal" or "numeric" => DbType.Decimal,
"float" => DbType.Double,
"uniqueidentifier" => DbType.Guid,
"smallint" => DbType.Int16,
"int" => DbType.Int32,
"bigint" => DbType.Int64,
"variant" => DbType.Object,
"varbinary" => DbType.Binary,
"varchar" or "nvarchar" or "geography" => DbType.String,
_ => throw new NotImplementedException($"Db type for {dataType} is not known"),
};
}
}

0 comments on commit 2c9c9eb

Please sign in to comment.