Skip to content

Commit 2cd6dfa

Browse files
committed
Removed SqlClient dependency from SqlLogWriter class and added more unit tests.
1 parent 97f8722 commit 2cd6dfa

File tree

4 files changed

+54
-23
lines changed

4 files changed

+54
-23
lines changed
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Data;
3-
using System.Data.Common;
44

55
namespace Serilog.Sinks.MSSqlServer.Sinks.MSSqlServer.Platform
66
{
77
internal interface ISqlCommandWrapper : IDisposable
88
{
99
CommandType CommandType { get; set; }
10-
DbParameterCollection Parameters { get; }
1110
string CommandText { get; set; }
1211

12+
void AddParameter(string parameterName, object value);
1313
int ExecuteNonQuery();
1414
}
1515
}

src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/Platform/SqlCommandWrapper.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Data;
34
using System.Data.Common;
45
#if NET452
@@ -25,14 +26,26 @@ public CommandType CommandType
2526
set => _sqlCommand.CommandType = value;
2627
}
2728

28-
public DbParameterCollection Parameters => _sqlCommand.Parameters;
29-
3029
public string CommandText
3130
{
3231
get => _sqlCommand.CommandText;
3332
set => _sqlCommand.CommandText = value;
3433
}
3534

35+
public void AddParameter(string parameterName, object value)
36+
{
37+
var parameter = new SqlParameter(parameterName, value ?? DBNull.Value);
38+
39+
// The default is SqlDbType.DateTime, which will truncate the DateTime value if the actual
40+
// type in the database table is datetime2. So we explicitly set it to DateTime2, which will
41+
// work both if the field in the table is datetime and datetime2, which is also consistent with
42+
// the behavior of the non-audit sink.
43+
if (value is DateTime)
44+
parameter.SqlDbType = SqlDbType.DateTime2;
45+
46+
_sqlCommand.Parameters.Add(parameter);
47+
}
48+
3649
public int ExecuteNonQuery() =>
3750
_sqlCommand.ExecuteNonQuery();
3851

src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/Platform/SqlLogEventWriter.cs

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
using System;
22
using System.Data;
3-
#if NET452
4-
using System.Data.SqlClient;
5-
#else
6-
using Microsoft.Data.SqlClient;
7-
#endif
83
using System.Text;
94
using Serilog.Debugging;
105
using Serilog.Events;
@@ -58,16 +53,7 @@ public void WriteEvent(LogEvent logEvent)
5853
parameterList.Append("@P");
5954
parameterList.Append(index);
6055

61-
var parameter = new SqlParameter($"@P{index}", field.Value ?? DBNull.Value);
62-
63-
// The default is SqlDbType.DateTime, which will truncate the DateTime value if the actual
64-
// type in the database table is datetime2. So we explicitly set it to DateTime2, which will
65-
// work both if the field in the table is datetime and datetime2, which is also consistent with
66-
// the behavior of the non-audit sink.
67-
if (field.Value is DateTime)
68-
parameter.SqlDbType = SqlDbType.DateTime2;
69-
70-
command.Parameters.Add(parameter);
56+
command.AddParameter($"@P{index}", field.Value);
7157

7258
index++;
7359
}

test/Serilog.Sinks.MSSqlServer.Tests/Sinks/MSSqlServer/Platform/SqlLogEventWriterTests.cs

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,19 +122,51 @@ public void WriteEventSetsSqlCommandWrapperCommandTypeText()
122122
}
123123

124124
[Fact]
125-
public void WriteEventSetsSqlCommandWrapperCommandTextToSqlInsertWithFields()
125+
public void WriteEventCallsSqlCommandWrapperAddParameterForEachField()
126126
{
127-
// TODO finish test
127+
// Arrange
128+
var logEvent = CreateLogEvent();
129+
var field1Value = "FieldValue1";
130+
var field2Value = 2;
131+
var field3Value = new DateTimeOffset(2020, 1, 1, 0, 0, 0, TimeSpan.Zero);
132+
var fieldsAndValues = new List<KeyValuePair<string, object>>
133+
{
134+
new KeyValuePair<string, object>("FieldName1", field1Value),
135+
new KeyValuePair<string, object>("FieldName2", field2Value),
136+
new KeyValuePair<string, object>("FieldNameThree", field3Value)
137+
};
138+
_logEventDataGeneratorMock.Setup(d => d.GetColumnsAndValues(It.IsAny<LogEvent>()))
139+
.Returns(fieldsAndValues);
140+
141+
// Act
142+
_sut.WriteEvent(logEvent);
128143

144+
// Assert
145+
_sqlCommandWrapperMock.Verify(c => c.AddParameter("@P0", field1Value), Times.Once);
146+
_sqlCommandWrapperMock.Verify(c => c.AddParameter("@P1", field2Value), Times.Once);
147+
_sqlCommandWrapperMock.Verify(c => c.AddParameter("@P2", field3Value), Times.Once);
148+
}
149+
150+
[Fact]
151+
public void WriteEventSetsSqlCommandWrapperCommandTextToSqlInsertWithCorrectFieldsAndValues()
152+
{
129153
// Arrange
154+
var expectedSqlCommandText = $"INSERT INTO [{_schemaName}].[{_tableName}] (FieldName1,FieldName2,FieldNameThree) VALUES (@P0,@P1,@P2)";
130155
var logEvent = CreateLogEvent();
131-
//_logEventDataGeneratorMock.Setup(...)
156+
var fieldsAndValues = new List<KeyValuePair<string, object>>
157+
{
158+
new KeyValuePair<string, object>("FieldName1", "FieldValue1"),
159+
new KeyValuePair<string, object>("FieldName2", 2),
160+
new KeyValuePair<string, object>("FieldNameThree", new DateTimeOffset(2020, 1, 1, 0, 0, 0, TimeSpan.Zero))
161+
};
162+
_logEventDataGeneratorMock.Setup(d => d.GetColumnsAndValues(It.IsAny<LogEvent>()))
163+
.Returns(fieldsAndValues);
132164

133165
// Act
134166
_sut.WriteEvent(logEvent);
135167

136168
// Assert
137-
//_sqlCommandWrapperMock.VerifySet(c => c.CommandText = expectedCommandText);
169+
_sqlCommandWrapperMock.VerifySet(c => c.CommandText = expectedSqlCommandText);
138170
}
139171

140172
[Fact]

0 commit comments

Comments
 (0)