Commit 86476bc2 authored by Marc Gravell's avatar Marc Gravell

(courtesy @mrange) fix dictionary semantics of DapperRow

parent eba9780e
...@@ -1327,7 +1327,7 @@ internal bool FieldExists(string key) ...@@ -1327,7 +1327,7 @@ internal bool FieldExists(string key)
sealed partial class DapperRowMetaObject : System.Dynamic.DynamicMetaObject sealed partial class DapperRowMetaObject : System.Dynamic.DynamicMetaObject
{ {
static readonly MethodInfo getValueMethod = typeof(IDictionary<string, object>).GetProperty("Item").GetGetMethod(); static readonly MethodInfo getValueMethod = typeof(IDictionary<string, object>).GetProperty("Item").GetGetMethod();
static readonly MethodInfo setValueMethod = typeof(DapperRow).GetMethod("SetValue"); static readonly MethodInfo setValueMethod = typeof(DapperRow).GetMethod("SetValue", new Type[] { typeof(string), typeof(object) });
public DapperRowMetaObject( public DapperRowMetaObject(
System.Linq.Expressions.Expression expression, System.Linq.Expressions.Expression expression,
...@@ -1546,8 +1546,7 @@ IEnumerator IEnumerable.GetEnumerator() ...@@ -1546,8 +1546,7 @@ IEnumerator IEnumerable.GetEnumerator()
void IDictionary<string, object>.Add(string key, object value) void IDictionary<string, object>.Add(string key, object value)
{ {
IDictionary<string, object> dic = this; SetValue(key, value, true);
dic[key] = value;
} }
bool IDictionary<string, object>.Remove(string key) bool IDictionary<string, object>.Remove(string key)
...@@ -1561,9 +1560,14 @@ IEnumerator IEnumerable.GetEnumerator() ...@@ -1561,9 +1560,14 @@ IEnumerator IEnumerable.GetEnumerator()
object IDictionary<string, object>.this[string key] object IDictionary<string, object>.this[string key]
{ {
get { object val; TryGetValue(key, out val); return val; } get { object val; TryGetValue(key, out val); return val; }
set { SetValue(key, value); } set { SetValue(key, value, false); }
} }
public object SetValue(string key, object value) public object SetValue(string key, object value)
{
return SetValue(key, value, false);
}
private object SetValue(string key, object value, bool isAdd)
{ {
if (key == null) throw new ArgumentNullException("key"); if (key == null) throw new ArgumentNullException("key");
int index = table.IndexOfName(key); int index = table.IndexOfName(key);
...@@ -1571,10 +1575,21 @@ public object SetValue(string key, object value) ...@@ -1571,10 +1575,21 @@ public object SetValue(string key, object value)
{ {
index = table.AddField(key); index = table.AddField(key);
} }
if (values.Length <= index) else if (isAdd && index < values.Length && !(values[index] is DeadValue))
{ // we'll assume they're doing lots of things, and {
// then semantically, this value already exists
throw new ArgumentException("An item with the same key has already been added", "key");
}
int oldLength = values.Length;
if (oldLength <= index)
{
// we'll assume they're doing lots of things, and
// grow it to the full width of the table // grow it to the full width of the table
Array.Resize(ref values, table.FieldCount); Array.Resize(ref values, table.FieldCount);
for (int i = oldLength; i < values.Length; i++)
{
values[i] = DeadValue.Default;
}
} }
return values[index] = value; return values[index] = value;
} }
......
...@@ -378,6 +378,40 @@ public void TestStrings() ...@@ -378,6 +378,40 @@ public void TestStrings()
.IsSequenceEqualTo(new[] { "a", "b" }); .IsSequenceEqualTo(new[] { "a", "b" });
} }
// see http://stackoverflow.com/questions/16726709/string-format-with-sql-wildcard-causing-dapper-query-to-break
public void CheckComplexConcat()
{
string end_wildcard = @"
SELECT * FROM #users16726709
WHERE (first_name LIKE CONCAT(@search_term, '%') OR last_name LIKE CONCAT(@search_term, '%'));";
string both_wildcards = @"
SELECT * FROM #users16726709
WHERE (first_name LIKE CONCAT('%', @search_term, '%') OR last_name LIKE CONCAT('%', @search_term, '%'));";
string formatted = @"
SELECT * FROM #users16726709
WHERE (first_name LIKE {0} OR last_name LIKE {0});";
string use_end_only = @"CONCAT(@search_term, '%')";
string use_both = @"CONCAT('%', @search_term, '%')";
// if true, slower query due to not being able to use indices, but will allow searching inside strings
bool allow_start_wildcards = false;
string query = String.Format(formatted, allow_start_wildcards ? use_both : use_end_only);
string term = "F"; // the term the user searched for
connection.Execute(@"create table #users16726709 (first_name varchar(200), last_name varchar(200))
insert #users16726709 values ('Fred','Bloggs') insert #users16726709 values ('Tony','Farcus') insert #users16726709 values ('Albert','Tenof')");
// Using Dapper
connection.Query(end_wildcard, new { search_term = term }).Count().IsEqualTo(2);
connection.Query(both_wildcards, new { search_term = term }).Count().IsEqualTo(3);
connection.Query(query, new { search_term = term }).Count().IsEqualTo(2);
}
enum EnumParam : short enum EnumParam : short
{ {
None, A, B None, A, B
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment