Skip to content

Commit

Permalink
Allow retrieving null instead of DBNull with GetValues.
Browse files Browse the repository at this point in the history
  • Loading branch information
jehugaleahsa committed Jun 4, 2019
1 parent b925f6d commit 8f886d7
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 36 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
## 4.6.0 (2019-06-03)
**Summary** - Support replacing `DBNull` with `null` when calling `GetValues` on an `IDataRecord`.

### New Features
When working with ADO.NET classes, you often have to deal with `null`s by checking for instances of `DBNull`. Most of the time, this involves calling `IDataRecord.IsDBNull()` or comparing values to `DBNull.Value`. The `DataRecordExtensions` class provides a lot of convenience methods, like `GetNullableString`, that save you from having to distinguish between `null` and `DBNull` all the time. The `FlatFileDataReader` and `DataTableExtensions` classes also provide a lot of features/options surrounding `null` handling. One area where this was overlooked was in the `DataRecordExtensions.GetValues` method.

It was decided that `object[] GetValues()` *(extension)* and `int GetValues(object[])` *(built-in)* should have similar semantics, so instead an optional parameter was added: `replaceDBNulls` that allows specifying whether `DBNull`s should be replaced in the destination array or not (defaults to keeping `DBNull`s). An additional extension: `int GetValues(object[], bool)` was added to provide similar semantics for the built-in method.

### Other
There were also some tests failing due to culture-specific date formatting. Those unit tests were updated to format dates in a culture-insensitive way.

## 4.5.0 (2019-05-29)
**Summary** - Disable wrapping delimited values in quotes.

Expand Down
80 changes: 55 additions & 25 deletions FlatFiles.Test/DataRecordExtensionsTester.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,6 @@ public void TestNullableExtensions_AllNotNull()
Assert.IsFalse(dataReader.Read(), "Too many records were read.");
}


[TestMethod]
public void TestGetValues_DbNullToNull()
{
var record = new MockDataRecord();
var values = record.GetValues();

Assert.AreEqual(6, values.Length);
Assert.AreEqual(null, values[2]);
}

private static SeparatedValueSchema GetSchema()
{
var mapper = SeparatedValueTypeMapper.Define(() => new NullableValues());
Expand Down Expand Up @@ -124,12 +113,60 @@ public class NullableValues
public DayOfWeek? EnumValue { get; set; }
}

private class MockDataRecord : IDataRecord
[TestMethod]
public void TestGetValues_DBNullToNull()
{
var record = new FakeDataRecord(new object[]
{
0, DateTime.UnixEpoch, DBNull.Value, 3.14159, 3.14159m, "A String"
});
var values = record.GetValues(replaceDBNulls: true);
Assert.AreEqual(6, values.Length);
Assert.AreEqual(null, values[2]);
}

[TestMethod]
public void TestGetValues_LargerArray()
{
private readonly object[] _values =
var record = new FakeDataRecord(new object[]
{
0, DateTime.UnixEpoch, DBNull.Value, 3.14159, 3.14159m, "A String"
});
var values = new object[10];
int length = record.GetValues(values);
Assert.AreEqual(6, length);
var expected = new object[]
{
0, DateTime.UnixEpoch, DBNull.Value, 3.14159, 3.14159m, "A String", null, null, null, null
};
CollectionAssert.AreEqual(expected, values);
}

[TestMethod]
public void TestGetValues_LargerArray_DBNullToNull()
{
var record = new FakeDataRecord(new object[]
{
0, DateTime.UnixEpoch, DBNull.Value, 3.14159, 3.14159m, "A String"
});
var values = new object[10];
int length = record.GetValues(values, replaceDBNulls: true);
Assert.AreEqual(6, length);
var expected = new object[]
{
0, DateTime.UnixEpoch, null, 3.14159, 3.14159m, "A String", null, null, null, null
};
CollectionAssert.AreEqual(expected, values);
}

private class FakeDataRecord : IDataRecord
{
public FakeDataRecord(object[] values)
{
Values = values;
}

public object[] Values { get; }

public bool GetBoolean(int i)
{
Expand Down Expand Up @@ -233,21 +270,14 @@ public object GetValue(int i)

public int GetValues(object[] values)
{
int i;
for (i = 0; i < values.Length && i < _values.Length; i++)
{
values[i] = _values[i];
}

return i;
int length = Math.Min(values.Length, Values.Length);
Array.Copy(Values, values, length);
return length;
}

public bool IsDBNull(int i)
{
throw new NotImplementedException();
}
public bool IsDBNull(int i) => Values[i] == null || Values[i] == DBNull.Value;

public int FieldCount => _values.Length;
public int FieldCount => Values.Length;

public object this[int i]
{
Expand Down
2 changes: 1 addition & 1 deletion FlatFiles.Test/DateTimeColumnTester.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public void TestParse_FormatProvider_FormatString_ParsesExactly()
InputFormat = "d",
FormatProvider = CultureInfo.InvariantCulture
};
DateTime actual = (DateTime)column.Parse(null, "1/19/2013");
DateTime actual = (DateTime)column.Parse(null, "01/19/2013");
DateTime expected = new DateTime(2013, 1, 19);
Assert.AreEqual(expected, actual);
}
Expand Down
29 changes: 23 additions & 6 deletions FlatFiles/DataRecordExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1018,19 +1018,36 @@ private static object ToEnum(Type type, object value)
/// Creates an array of objects with the column values of the current record.
/// </summary>
/// <param name="record">The IDataRecord to get the values for.</param>
/// <param name="replaceDBNulls">Indicates whether DBNull instances should be replaced with nulls.</param>
/// <returns>An array of objects with the column values of the current record.</returns>
public static object[] GetValues(this IDataRecord record)
public static object[] GetValues(this IDataRecord record, bool replaceDBNulls = false)
{
var values = new object[record.FieldCount];
record.GetValues(values);
for (int i = 0; i < values.Length; i++)
record.GetValues(values, replaceDBNulls);
return values;
}

/// <summary>
/// Populates an array of objects with the column values of the current record.
/// </summary>
/// <param name="record">The IDataRecord to get the values for.</param>
/// <param name="values">The array to store the values in.</param>
/// <param name="replaceDBNulls">Indicates whether DBNull instances should be replaced with nulls.</param>
/// <returns>The number of objects copied to the array.</returns>
public static int GetValues(this IDataRecord record, object[] values, bool replaceDBNulls)
{
int result = record.GetValues(values);
if (replaceDBNulls)
{
if (values[i] == DBNull.Value)
for (int index = 0; index != result; ++index)
{
values[i] = null;
if (values[index] == DBNull.Value)
{
values[index] = null;
}
}
}
return values;
return result;
}

#endregion
Expand Down
8 changes: 4 additions & 4 deletions FlatFiles/FlatFiles.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
<RepositoryUrl>https://github.com/jehugaleahsa/FlatFiles.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>csv;comma;tab;separated;value;delimited;flat;file;fixed;width;fixed-width;length;fixed-length;parser;parsing;parse</PackageTags>
<PackageReleaseNotes>Allow disabling quotes in delimited files.</PackageReleaseNotes>
<PackageReleaseNotes>Support replacing DBNull with null when reading from IDataRecord.</PackageReleaseNotes>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>FlatFiles.snk</AssemblyOriginatorKeyFile>
<Version>4.5.0</Version>
<Version>4.6.0</Version>
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'net451' ">
Expand All @@ -27,8 +27,8 @@
<PropertyGroup>
<LangVersion>7.3</LangVersion>
<PackageIconUrl>https://raw.githubusercontent.com/jehugaleahsa/FlatFiles/master/icon.png</PackageIconUrl>
<AssemblyVersion>4.5.0.0</AssemblyVersion>
<FileVersion>4.5.0.0</FileVersion>
<AssemblyVersion>4.6.0.0</AssemblyVersion>
<FileVersion>4.6.0.0</FileVersion>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard1.6|AnyCPU'">
Expand Down

0 comments on commit 8f886d7

Please sign in to comment.