From 0bdc2ca14b86b3f7812b29cc2e40e4460e6feaa3 Mon Sep 17 00:00:00 2001 From: Jonas Goronczy Date: Thu, 16 Jun 2022 15:02:29 +0200 Subject: [PATCH] Adds MatchConstructorParametersWithUnderscores option --- Dapper/DefaultTypeMap.cs | 27 ++++++++++++++++++++++----- tests/Dapper.Tests/MiscTests.cs | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/Dapper/DefaultTypeMap.cs b/Dapper/DefaultTypeMap.cs index b278250c..1c46f525 100644 --- a/Dapper/DefaultTypeMap.cs +++ b/Dapper/DefaultTypeMap.cs @@ -74,7 +74,8 @@ public ConstructorInfo FindConstructor(string[] names, Type[] types) int i = 0; for (; i < ctorParameters.Length; i++) { - if (!string.Equals(ctorParameters[i].Name, names[i], StringComparison.OrdinalIgnoreCase)) + var denseName = MatchConstructorParametersWithUnderscores ? names[i].Replace("_", "") : names[i]; + if (!string.Equals(ctorParameters[i].Name, denseName, StringComparison.OrdinalIgnoreCase)) break; if (types[i] == typeof(byte[]) && ctorParameters[i].ParameterType.FullName == SqlMapper.LinqBinary) continue; @@ -120,8 +121,9 @@ public ConstructorInfo FindExplicitConstructor() public SqlMapper.IMemberMap GetConstructorParameter(ConstructorInfo constructor, string columnName) { var parameters = constructor.GetParameters(); + var denseColumnName = MatchConstructorParametersWithUnderscores ? columnName.Replace("_", "") : columnName; - return new SimpleMemberMap(columnName, parameters.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase))); + return new SimpleMemberMap(columnName, parameters.FirstOrDefault(p => string.Equals(p.Name, denseColumnName, StringComparison.OrdinalIgnoreCase))); } /// @@ -134,7 +136,7 @@ public SqlMapper.IMemberMap GetMember(string columnName) var property = Properties.Find(p => string.Equals(p.Name, columnName, StringComparison.Ordinal)) ?? Properties.Find(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase)); - if (property == null && MatchNamesWithUnderscores) + if (property == null && MatchFieldsAndPropertiesWithUnderscores) { property = Properties.Find(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.Ordinal)) ?? Properties.Find(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.OrdinalIgnoreCase)); @@ -153,7 +155,7 @@ public SqlMapper.IMemberMap GetMember(string columnName) ?? _fields.Find(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase)) ?? _fields.Find(p => string.Equals(p.Name, backingFieldName, StringComparison.OrdinalIgnoreCase)); - if (field == null && MatchNamesWithUnderscores) + if (field == null && MatchFieldsAndPropertiesWithUnderscores) { var effectiveColumnName = columnName.Replace("_", ""); backingFieldName = "<" + effectiveColumnName + ">k__BackingField"; @@ -172,7 +174,22 @@ public SqlMapper.IMemberMap GetMember(string columnName) /// /// Should column names like User_Id be allowed to match properties/fields like UserId ? /// - public static bool MatchNamesWithUnderscores { get; set; } + [Obsolete("Use MatchFieldsAndPropertiesWithUnderscores for clarity")] + public static bool MatchNamesWithUnderscores + { + get { return MatchFieldsAndPropertiesWithUnderscores; } + set { MatchFieldsAndPropertiesWithUnderscores = value; } + } + + /// + /// Should column names like User_Id be allowed to match properties/fields like UserId ? + /// + public static bool MatchFieldsAndPropertiesWithUnderscores { get; set; } + + /// + /// Should column names like User_Id be allowed to match constructor arguments like userId ? + /// + public static bool MatchConstructorParametersWithUnderscores { get; set; } /// /// The settable properties for this typemap diff --git a/tests/Dapper.Tests/MiscTests.cs b/tests/Dapper.Tests/MiscTests.cs index 4d5dd26c..9cff3b04 100644 --- a/tests/Dapper.Tests/MiscTests.cs +++ b/tests/Dapper.Tests/MiscTests.cs @@ -1273,5 +1273,27 @@ private class HazGetOnly public int Id { get; } public string Name { get; } = "abc"; } + + [Fact] + public void TestConstructorParametersWithUnderscoredColumns() + { + DefaultTypeMap.MatchConstructorParametersWithUnderscores = true; + DefaultTypeMap.MatchFieldsAndPropertiesWithUnderscores = true; + var obj = connection.QuerySingle("select 42 as [id_property], 'def' as [name_property];"); + Assert.Equal(42, obj.IdProperty); + Assert.Equal("def", obj.NameProperty); + } + + private class HazGetOnlyAndCtor + { + public int IdProperty { get; } + public string NameProperty { get; } + + public HazGetOnlyAndCtor(int idProperty, string nameProperty) + { + IdProperty = idProperty; + NameProperty = nameProperty; + } + } } }