Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit c1ca2b4

Browse files
authored
Merge pull request #517 from shift-evgeny/ColumnGuessingFix
Do not guess column mapping when an exact match is found for a requested column
2 parents ac22464 + ce7584e commit c1ca2b4

File tree

5 files changed

+82
-11
lines changed

5 files changed

+82
-11
lines changed

src/ServiceStack.OrmLite/FieldDefinition.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ public string GetQuotedValue(object fromInstance, IOrmLiteDialectProvider dialec
100100

101101
public bool IsRefType { get; set; }
102102

103+
public override string ToString()
104+
{
105+
return Name;
106+
}
107+
103108
public bool ShouldSkipInsert()
104109
{
105110
return AutoIncrement || IsComputed || IsRowVersion;

src/ServiceStack.OrmLite/ModelDefinition.cs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,15 +123,26 @@ public FieldDefinition GetFieldDefinition<T>(Expression<Func<T, object>> field)
123123

124124
public FieldDefinition GetFieldDefinition(string fieldName)
125125
{
126-
if (fieldName != null)
126+
if (fieldName == null)
127+
return null;
128+
129+
var comparison = StringComparison.OrdinalIgnoreCase;
130+
FieldDefinition bestMatch = null;
131+
132+
for (var i = 0; i < FieldDefinitionsArray.Length; ++i)
127133
{
128-
foreach (var f in FieldDefinitionsArray)
134+
if (string.Equals(FieldDefinitionsArray[i].Name, fieldName, comparison))
129135
{
130-
if (string.Equals(f.Name, fieldName, StringComparison.OrdinalIgnoreCase))
131-
return f;
136+
bestMatch = FieldDefinitionsArray[i];
137+
if (comparison == StringComparison.Ordinal)
138+
return bestMatch;
139+
140+
comparison = StringComparison.Ordinal; // Keep looking for a better match
141+
--i; // Check the current field again, now using case-sensitive comparison
132142
}
133143
}
134-
return null;
144+
145+
return bestMatch;
135146
}
136147

137148
public void AfterInit()

src/ServiceStack.OrmLite/OrmLiteUtils.cs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,7 @@ public static Tuple<FieldDefinition, int, IOrmLiteConverter>[] GetIndexFieldsCac
496496
.Where(x => !ignoredFields.Contains(x) && x.SetValueFn != null).ToList();
497497

498498
var end = endPos.GetValueOrDefault(reader.FieldCount);
499+
var mappedReaderColumns = new bool[end];
499500

500501
for (var i = startPos; i < end; i++)
501502
{
@@ -517,6 +518,7 @@ public static Tuple<FieldDefinition, int, IOrmLiteConverter>[] GetIndexFieldsCac
517518
if (fieldDef != null && !ignoredFields.Contains(fieldDef) && fieldDef.SetValueFn != null)
518519
{
519520
remainingFieldDefs.Remove(fieldDef);
521+
mappedReaderColumns[i] = true;
520522
cache.Add(Tuple.Create(fieldDef, i, dialect.GetConverterBestMatch(fieldDef)));
521523
}
522524
}
@@ -526,16 +528,22 @@ public static Tuple<FieldDefinition, int, IOrmLiteConverter>[] GetIndexFieldsCac
526528
var dbFieldMap = new Dictionary<string, int>(StringComparer.InvariantCultureIgnoreCase);
527529
for (var i = startPos; i < end; i++)
528530
{
529-
var fieldName = reader.GetName(i);
530-
dbFieldMap[fieldName] = i;
531+
if (!mappedReaderColumns[i])
532+
{
533+
var fieldName = reader.GetName(i);
534+
dbFieldMap[fieldName] = i;
535+
}
531536
}
532537

533-
foreach (var fieldDef in remainingFieldDefs)
538+
if (dbFieldMap.Count > 0)
534539
{
535-
var index = FindColumnIndex(dialect, fieldDef, dbFieldMap);
536-
if (index != NotFound)
540+
foreach (var fieldDef in remainingFieldDefs)
537541
{
538-
cache.Add(Tuple.Create(fieldDef, index, dialect.GetConverterBestMatch(fieldDef)));
542+
var index = FindColumnIndex(dialect, fieldDef, dbFieldMap);
543+
if (index != NotFound)
544+
{
545+
cache.Add(Tuple.Create(fieldDef, index, dialect.GetConverterBestMatch(fieldDef)));
546+
}
539547
}
540548
}
541549
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using System.Linq;
2+
using NUnit.Framework;
3+
using ServiceStack.Text;
4+
5+
namespace ServiceStack.OrmLite.Tests.Issues
6+
{
7+
[TestFixture]
8+
public class ColumnGuessingTests : OrmLiteTestBase
9+
{
10+
private class Person
11+
{
12+
public string Name { get; set; }
13+
public string LastName { get; set; }
14+
public string NameAtBirth { get; set; }
15+
}
16+
17+
[Test]
18+
public void Dont_guess_extra_columns_when_match_found()
19+
{
20+
// Only the specified column should be selected. The value of Name should not be written to FirstName nor NameAtBirth,
21+
// since there is already a match for the requested column in the data model class.
22+
23+
using (var db = OpenDbConnection())
24+
{
25+
db.DropAndCreateTable<Person>();
26+
db.Insert(new Person { LastName = "Smith", Name = "John", NameAtBirth = "Black" });
27+
28+
var row = db.Select(db.From<Person>().Select(r => new { r.LastName })).Single();
29+
AssertPerson(new Person { LastName = "Smith" }, row);
30+
31+
row = db.Select(db.From<Person>().Select(r => new { r.Name })).Single();
32+
AssertPerson(new Person { Name = "John" }, row);
33+
34+
row = db.Select(db.From<Person>().Select(r => new { r.NameAtBirth })).Single();
35+
AssertPerson(new Person { NameAtBirth = "Black" }, row);
36+
}
37+
}
38+
39+
private static void AssertPerson(Person expected, Person actual)
40+
{
41+
Assert.AreEqual(expected.Name, actual.Name, "Name differs");
42+
Assert.AreEqual(expected.LastName, actual.LastName, "LastName differs");
43+
Assert.AreEqual(expected.NameAtBirth, actual.NameAtBirth, "NameAtBirth differs");
44+
}
45+
}
46+
}

tests/ServiceStack.OrmLite.Tests/ServiceStack.OrmLite.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@
130130
<Compile Include="DefaultValueTests.cs" />
131131
<Compile Include="Issues\BelongsToIssue.cs" />
132132
<Compile Include="Issues\CanBuildExpressionWithAbstractType.cs" />
133+
<Compile Include="Issues\ColumnGuessingTests.cs" />
133134
<Compile Include="Issues\JoinBoolSqlServerIssue.cs" />
134135
<Compile Include="Issues\MergingNestedSqlExpressionIssue.cs" />
135136
<Compile Include="Issues\SqlExpressionSubSqlExpressionIssue.cs" />

0 commit comments

Comments
 (0)