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

Commit cd7c790

Browse files
committed
Resolve nullable params in anon types issue
1 parent 257449c commit cd7c790

File tree

2 files changed

+261
-1
lines changed

2 files changed

+261
-1
lines changed

src/ServiceStack.OrmLite/OrmLiteReadCommandExtensions.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,11 +230,15 @@ internal static IDbCommand SetParameters(this IDbCommand dbCmd, Type type, objec
230230
: null;
231231

232232
var sqlCopy = sql; //C# doesn't allow changing ref params in lambda's
233+
Dictionary<string, PropertyAccessor> anonTypeProps = null;
233234

234235
var paramIndex = 0;
235236
anonType.ToObjectDictionary().ForEachParam(modelDef, excludeDefaults, (propName, columnName, value) =>
236237
{
237-
var propType = value?.GetType() ?? typeof(object);
238+
var propType = value?.GetType() ?? ((anonTypeProps ??= TypeProperties.Get(anonType.GetType()).PropertyMap)
239+
.TryGetValue(propName, out var pType)
240+
? pType.PropertyInfo.PropertyType
241+
: typeof(object));
238242
var inValues = GetMultiValues(value);
239243
if (inValues != null)
240244
{
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
using NUnit.Framework;
2+
using ServiceStack.OrmLite.Tests;
3+
using ServiceStack.Text;
4+
5+
namespace ServiceStack.OrmLite.PostgreSQL.Tests.Issues
6+
{
7+
[TestFixtureOrmLiteDialects(Dialect.AnyPostgreSql)]
8+
public class StoredProcNullableParams : OrmLiteProvidersTestBase
9+
{
10+
public StoredProcNullableParams(DialectContext context) : base(context) {}
11+
/*
12+
* Nullable Type tests
13+
* NOTE: These test only test SqlList<T> they should probably also test Select<T>
14+
*/
15+
16+
private const string CreateFunction = @"
17+
CREATE OR REPLACE FUNCTION f_service_stack_function_{0}(
18+
v_{0} {0}
19+
) RETURNS TABLE (
20+
id int,
21+
val {0}
22+
) AS
23+
$BODY$
24+
BEGIN
25+
-- generate rows 1 - 10, but with the same val to make it look like a table.
26+
RETURN QUERY SELECT s AS id, v_{0} AS val FROM generate_series(1,10) s;
27+
END;
28+
$BODY$
29+
LANGUAGE plpgsql VOLATILE COST 100;
30+
";
31+
32+
private const string DropFunction = "DROP FUNCTION IF EXISTS f_service_stack_function_{0}({0});";
33+
34+
35+
public class ServiceStackTypeFunctionResultNullableInt
36+
{
37+
public int Id { get; set; }
38+
public int? Val { get; set; }
39+
}
40+
41+
[Test]
42+
public void Can_execute_function_with_nullable_int_param()
43+
{
44+
using (var db = OpenDbConnection())
45+
{
46+
const string pgTypeToTest = "int";
47+
int? testVal = null;
48+
49+
// if function already exists drop before create (can't change result)
50+
db.ExecuteSql(DropFunction.Fmt(pgTypeToTest));
51+
52+
db.ExecuteSql(CreateFunction.Fmt(pgTypeToTest));
53+
db.GetLastSql().Print();
54+
55+
// Fix: DbCommand.Parameter for NULL values defaults to NpgsqlTypes.NpgsqlDbType.Text should be NpgsqlTypes.NpgsqlDbType.Integer
56+
57+
var sql = "SELECT * FROM f_service_stack_function_{0}(@paramValue);".Fmt(pgTypeToTest);
58+
59+
var rows = db.SqlList<ServiceStackTypeFunctionResultNullableInt>(
60+
sql,
61+
new
62+
{
63+
paramValue = testVal
64+
});
65+
66+
Assert.That(rows.Count, Is.EqualTo((10)));
67+
Assert.That(rows[0].Val, Is.Null);
68+
69+
db.ExecuteSql(DropFunction.Fmt(pgTypeToTest));
70+
}
71+
}
72+
73+
public class ServiceStackTypeFunctionResultNullableShort
74+
{
75+
public int Id { get; set; }
76+
public short? Val { get; set; }
77+
}
78+
79+
[Test]
80+
public void Can_execute_function_with_nullable_short_param()
81+
{
82+
using (var db = OpenDbConnection())
83+
{
84+
const string pgTypeToTest = "smallint";
85+
short? testVal = null;
86+
87+
// if function already exists drop before create (can't change result)
88+
db.ExecuteSql(DropFunction.Fmt(pgTypeToTest));
89+
90+
db.ExecuteSql(CreateFunction.Fmt(pgTypeToTest));
91+
db.GetLastSql().Print();
92+
93+
// Fix: DbCommand.Parameter for NULL values defaults to NpgsqlTypes.NpgsqlDbType.Text should be NpgsqlTypes.NpgsqlDbType.Smallint
94+
95+
var sql = "SELECT * FROM f_service_stack_function_{0}(@paramValue);".Fmt(pgTypeToTest);
96+
97+
var rows = db.SqlList<ServiceStackTypeFunctionResultNullableShort>(
98+
sql,
99+
new
100+
{
101+
paramValue = testVal
102+
});
103+
104+
Assert.That(rows.Count, Is.EqualTo((10)));
105+
Assert.That(rows[0].Val, Is.Null);
106+
107+
db.ExecuteSql(DropFunction.Fmt(pgTypeToTest));
108+
}
109+
}
110+
111+
public class ServiceStackTypeFunctionResultNullableLong
112+
{
113+
public int Id { get; set; }
114+
public long? Val { get; set; }
115+
}
116+
117+
[Test]
118+
public void Can_execute_function_with_nullable_long_param()
119+
{
120+
using (var db = OpenDbConnection())
121+
{
122+
const string pgTypeToTest = "bigint";
123+
long? testVal = null;
124+
125+
// if function already exists drop before create (can't change result)
126+
db.ExecuteSql(DropFunction.Fmt(pgTypeToTest));
127+
128+
db.ExecuteSql(CreateFunction.Fmt(pgTypeToTest));
129+
db.GetLastSql().Print();
130+
131+
// Fix: DbCommand.Parameter for NULL values defaults to NpgsqlTypes.NpgsqlDbType.Text should be NpgsqlTypes.NpgsqlDbType.Bigint
132+
133+
var sql = "SELECT * FROM f_service_stack_function_{0}(@paramValue);".Fmt(pgTypeToTest);
134+
135+
var rows = db.SqlList<ServiceStackTypeFunctionResultNullableLong>(
136+
sql,
137+
new
138+
{
139+
paramValue = testVal
140+
});
141+
142+
Assert.That(rows.Count, Is.EqualTo((10)));
143+
Assert.That(rows[0].Val, Is.Null);
144+
145+
db.ExecuteSql(DropFunction.Fmt(pgTypeToTest));
146+
}
147+
}
148+
149+
public class ServiceStackTypeFunctionResultInt
150+
{
151+
public int Id { get; set; }
152+
public int Val { get; set; }
153+
}
154+
155+
[Test]
156+
public void Can_execute_function_with_int_param()
157+
{
158+
using (var db = OpenDbConnection())
159+
{
160+
const string pgTypeToTest = "int";
161+
const int testVal = 123;
162+
163+
// if function already exists drop before create (can't change result)
164+
db.ExecuteSql(DropFunction.Fmt(pgTypeToTest));
165+
166+
db.ExecuteSql(CreateFunction.Fmt(pgTypeToTest));
167+
db.GetLastSql().Print();
168+
169+
var sql = "SELECT * FROM f_service_stack_function_{0}(@paramValue);".Fmt(pgTypeToTest);
170+
171+
var rows = db.SqlList<ServiceStackTypeFunctionResultInt>(
172+
sql,
173+
new {
174+
paramValue = testVal
175+
});
176+
177+
Assert.That(rows.Count, Is.EqualTo((10)));
178+
Assert.That(rows[0].Val, Is.EqualTo(testVal));
179+
180+
db.ExecuteSql(DropFunction.Fmt(pgTypeToTest));
181+
}
182+
}
183+
184+
public class ServiceStackTypeFunctionResultShort
185+
{
186+
public int Id { get; set; }
187+
public short Val { get; set; }
188+
}
189+
190+
[Test]
191+
public void Can_execute_function_with_short_param()
192+
{
193+
using (var db = OpenDbConnection())
194+
{
195+
const string pgTypeToTest = "smallint";
196+
const short testVal = 123;
197+
198+
// if function already exists drop before create (can't change result)
199+
db.ExecuteSql(DropFunction.Fmt(pgTypeToTest));
200+
201+
db.ExecuteSql(CreateFunction.Fmt(pgTypeToTest));
202+
db.GetLastSql().Print();
203+
204+
var sql = "SELECT * FROM f_service_stack_function_{0}(@paramValue);".Fmt(pgTypeToTest);
205+
206+
var rows = db.SqlList<ServiceStackTypeFunctionResultShort>(
207+
sql, new {
208+
paramValue = testVal
209+
});
210+
211+
Assert.That(rows.Count, Is.EqualTo((10)));
212+
Assert.That(rows[0].Val, Is.EqualTo(testVal));
213+
214+
db.ExecuteSql(DropFunction.Fmt(pgTypeToTest));
215+
}
216+
}
217+
218+
public class ServiceStackTypeFunctionResultLong
219+
{
220+
public int Id { get; set; }
221+
public long Val { get; set; }
222+
}
223+
224+
[Test]
225+
public void Can_execute_function_with_long_param()
226+
{
227+
using (var db = OpenDbConnection())
228+
{
229+
const string pgTypeToTest = "bigint";
230+
const long testVal = long.MaxValue - 100;
231+
232+
// if function already exists drop before create (can't change result)
233+
db.ExecuteSql(DropFunction.Fmt(pgTypeToTest));
234+
// Make sure there isn't an INT function to fallback to.
235+
db.ExecuteSql(DropFunction.Fmt("int"));
236+
237+
238+
db.ExecuteSql(CreateFunction.Fmt(pgTypeToTest));
239+
db.GetLastSql().Print();
240+
241+
var sql = "SELECT * FROM f_service_stack_function_{0}(@paramValue);".Fmt(pgTypeToTest);
242+
243+
var rows = db.SqlList<ServiceStackTypeFunctionResultLong>(
244+
sql,
245+
new {
246+
paramValue = testVal
247+
});
248+
249+
Assert.That(rows.Count, Is.EqualTo((10)));
250+
Assert.That(rows[0].Val, Is.EqualTo(testVal));
251+
252+
db.ExecuteSql(DropFunction.Fmt(pgTypeToTest));
253+
}
254+
}
255+
}
256+
}

0 commit comments

Comments
 (0)