markus / ConvertService / ServiceBase / Markus.Service.DataBase.Dapper / MixParameters.cs @ d952e1d5
이력 | 보기 | 이력해설 | 다운로드 (10.7 KB)
1 |
using Dapper; |
---|---|
2 |
using Npgsql; |
3 |
using NpgsqlTypes; |
4 |
using System; |
5 |
using System.Collections.Generic; |
6 |
using System.Data; |
7 |
using System.Linq; |
8 |
|
9 |
namespace Markus.Service.DataBase |
10 |
{ |
11 |
internal class MixParameters : SqlMapper.IDynamicParameters, SqlMapper.IParameterLookup |
12 |
{ |
13 |
public MixParameters(DBMSType dbms) |
14 |
{ |
15 |
DBMS = dbms; |
16 |
} |
17 |
|
18 |
private DBMSType DBMS = DBMSType.MSSQL; |
19 |
|
20 |
internal const DbType EnumerableMultiParameter = (DbType)(-1); |
21 |
private static readonly Dictionary<SqlMapper.Identity, Action<IDbCommand, object>> paramReaderCache = new Dictionary<SqlMapper.Identity, Action<IDbCommand, object>>(); |
22 |
private readonly Dictionary<string, ParamInfo> _parameters = new Dictionary<string, ParamInfo>(); |
23 |
private List<object> templates; |
24 |
|
25 |
/// <summary> |
26 |
/// All the names of the param in the bag, use Get to yank them out |
27 |
/// </summary> |
28 |
public IEnumerable<string> ParameterNames |
29 |
{ |
30 |
get { return _parameters.Select(p => p.Key); } |
31 |
} |
32 |
|
33 |
public int ParameterCount |
34 |
{ |
35 |
get { return _parameters.Count; } |
36 |
} |
37 |
|
38 |
object SqlMapper.IParameterLookup.this[string name] => |
39 |
_parameters.TryGetValue(name, out ParamInfo param) ? param.Value : null; |
40 |
|
41 |
internal static bool ShouldSetDbType(DbType? dbType) |
42 |
=> dbType.HasValue && dbType.GetValueOrDefault() != EnumerableMultiParameter; |
43 |
|
44 |
internal static bool ShouldSetDbType(DbType dbType) |
45 |
=> dbType != EnumerableMultiParameter; // just in case called with non-nullable |
46 |
|
47 |
void SqlMapper.IDynamicParameters.AddParameters(IDbCommand command, SqlMapper.Identity identity) |
48 |
{ |
49 |
if (templates != null) |
50 |
foreach (var template in templates) |
51 |
{ |
52 |
var newIdent = identity.ForDynamicParameters(template.GetType()); |
53 |
Action<IDbCommand, object> appender; |
54 |
|
55 |
lock (paramReaderCache) |
56 |
{ |
57 |
if (!paramReaderCache.TryGetValue(newIdent, out appender)) |
58 |
{ |
59 |
appender = SqlMapper.CreateParamInfoGenerator(newIdent, false, true); |
60 |
paramReaderCache[newIdent] = appender; |
61 |
} |
62 |
} |
63 |
|
64 |
appender(command, template); |
65 |
} |
66 |
|
67 |
switch (DBMS) |
68 |
{ |
69 |
case DBMSType.POSTGRESQL: |
70 |
case DBMSType.MSSQL: |
71 |
msSqlAddParamaters(command, identity); |
72 |
break; |
73 |
//case DBMSType.POSTGRESQL: |
74 |
// npgAddParamaters(command, identity); |
75 |
//break; |
76 |
default: |
77 |
break; |
78 |
} |
79 |
} |
80 |
|
81 |
private void msSqlAddParamaters(IDbCommand command, SqlMapper.Identity identity) |
82 |
{ |
83 |
foreach (var param in _parameters.Values) |
84 |
{ |
85 |
if (param.CameFromTemplate) continue; |
86 |
|
87 |
var dbType = param.DbType; |
88 |
var val = param.Value; |
89 |
string name = Clean(param.Name); |
90 |
var isCustomQueryParameter = val is SqlMapper.ICustomQueryParameter; |
91 |
|
92 |
SqlMapper.ITypeHandler handler = null; |
93 |
if (dbType == null && val != null && !isCustomQueryParameter) |
94 |
{ |
95 |
#pragma warning disable 618 |
96 |
dbType = SqlMapper.LookupDbType(val.GetType(), name, true, out handler); |
97 |
#pragma warning disable 618 |
98 |
} |
99 |
if (isCustomQueryParameter) |
100 |
{ |
101 |
((SqlMapper.ICustomQueryParameter)val).AddParameter(command, name); |
102 |
} |
103 |
else if (dbType == EnumerableMultiParameter) |
104 |
{ |
105 |
#pragma warning disable 612, 618 |
106 |
SqlMapper.PackListParameters(command, name, val); |
107 |
#pragma warning restore 612, 618 |
108 |
} |
109 |
else |
110 |
{ |
111 |
bool add = !command.Parameters.Contains(name); |
112 |
IDbDataParameter p; |
113 |
if (add) |
114 |
{ |
115 |
p = command.CreateParameter(); |
116 |
p.ParameterName = name; |
117 |
} |
118 |
else |
119 |
{ |
120 |
p = (IDbDataParameter)command.Parameters[name]; |
121 |
} |
122 |
|
123 |
p.Direction = param.ParameterDirection; |
124 |
if (handler == null) |
125 |
{ |
126 |
#pragma warning disable 0618 |
127 |
p.Value = SqlMapper.SanitizeParameterValue(val); |
128 |
#pragma warning restore 0618 |
129 |
if (ShouldSetDbType(dbType) && p.DbType != dbType.GetValueOrDefault()) |
130 |
{ |
131 |
p.DbType = dbType.GetValueOrDefault(); |
132 |
} |
133 |
var s = val as string; |
134 |
if (s?.Length <= DbString.DefaultLength) |
135 |
{ |
136 |
p.Size = DbString.DefaultLength; |
137 |
} |
138 |
if (param.Size != null) p.Size = param.Size.Value; |
139 |
if (param.Precision != null) p.Precision = param.Precision.Value; |
140 |
if (param.Scale != null) p.Scale = param.Scale.Value; |
141 |
} |
142 |
else |
143 |
{ |
144 |
if (ShouldSetDbType(dbType)) p.DbType = dbType.GetValueOrDefault(); |
145 |
if (param.Size != null) p.Size = param.Size.Value; |
146 |
if (param.Precision != null) p.Precision = param.Precision.Value; |
147 |
if (param.Scale != null) p.Scale = param.Scale.Value; |
148 |
handler.SetValue(p, val ?? DBNull.Value); |
149 |
} |
150 |
|
151 |
if (add) |
152 |
{ |
153 |
command.Parameters.Add(p); |
154 |
} |
155 |
param.AttachedParam = p; |
156 |
} |
157 |
} |
158 |
|
159 |
// note: most non-privileged implementations would use: this.ReplaceLiterals(command); |
160 |
//if (literals.Count != 0) SqlMapper.ReplaceLiterals(this, command); |
161 |
} |
162 |
|
163 |
private void npgAddParamaters(IDbCommand command, SqlMapper.Identity identity) |
164 |
{ |
165 |
foreach (var param in _parameters.Values) |
166 |
{ |
167 |
if (((NpgsqlCommand)command).Parameters.Contains(param.Name)) |
168 |
{ |
169 |
((NpgsqlCommand)command).Parameters.Remove(param.Name); |
170 |
} |
171 |
|
172 |
var p = ParamInfoToNpgParam(param); |
173 |
p.ParameterName = param.Name; |
174 |
|
175 |
command.Parameters.Add(p); |
176 |
|
177 |
param.AttachedParam = p; |
178 |
} |
179 |
} |
180 |
|
181 |
private NpgsqlParameter ParamInfoToNpgParam(ParamInfo param) |
182 |
{ |
183 |
NpgsqlParameter p = new NpgsqlParameter(); |
184 |
|
185 |
var val = param.Value; |
186 |
p.Value = val ?? DBNull.Value; |
187 |
p.Direction = param.ParameterDirection; |
188 |
if (param.Size != null) p.Size = param.Size.Value; |
189 |
if (param.NpgsqlType != null) |
190 |
{ |
191 |
p.NpgsqlDbType = param.NpgsqlType.Value; |
192 |
} |
193 |
else if (param.Value != null) |
194 |
{ |
195 |
var npgType = dbTypeConvert.GetNpgsqlDbType(param.Value.GetType()).Value; |
196 |
|
197 |
if (npgType == NpgsqlDbType.Text) |
198 |
{ |
199 |
//npgType = NpgsqlDbType.Varchar; |
200 |
} |
201 |
|
202 |
p.NpgsqlDbType = npgType; |
203 |
} |
204 |
else if (param.DbType != null) |
205 |
{ |
206 |
var npgType = dbTypeConvert.GetNpgsqlDbType(param.DbType.Value).Value; |
207 |
|
208 |
if (npgType == NpgsqlDbType.Text) |
209 |
{ |
210 |
//npgType = NpgsqlDbType.Varchar; |
211 |
} |
212 |
|
213 |
p.NpgsqlDbType = npgType; |
214 |
} |
215 |
else |
216 |
{ |
217 |
throw new Exception($"{param.Name} npgSQL type을 알 수 없습니다."); |
218 |
} |
219 |
|
220 |
return p; |
221 |
} |
222 |
|
223 |
private static string Clean(string name) |
224 |
{ |
225 |
if (!string.IsNullOrEmpty(name)) |
226 |
{ |
227 |
switch (name[0]) |
228 |
{ |
229 |
case '@': |
230 |
case ':': |
231 |
case '?': |
232 |
return name.Substring(1); |
233 |
} |
234 |
} |
235 |
return name; |
236 |
} |
237 |
internal void Add(string name,object value = null,NpgsqlTypes.NpgsqlDbType? npgsqlDbType = null, DbType? dbType = null, ParameterDirection? direction = null, int? size = null) |
238 |
{ |
239 |
if(DBMS == DBMSType.MSSQL) |
240 |
{ |
241 |
switch (direction) |
242 |
{ |
243 |
case ParameterDirection.Output: |
244 |
case ParameterDirection.InputOutput: |
245 |
if(size == null) |
246 |
{ |
247 |
size = 50; |
248 |
//throw new Exception($"{name}는 MSSQL인 경우 direction이 {direction.ToString()}이므로 size를 지정하여야 합니다."); |
249 |
} |
250 |
break; |
251 |
default: |
252 |
break; |
253 |
} |
254 |
} |
255 |
|
256 |
_parameters[Clean(name)] = new ParamInfo |
257 |
{ |
258 |
Name = name, |
259 |
Value = value, |
260 |
ParameterDirection = direction ?? ParameterDirection.Input, |
261 |
DbType = dbType, |
262 |
NpgsqlType = npgsqlDbType, |
263 |
Size = size |
264 |
}; |
265 |
} |
266 |
|
267 |
internal T Get<T>(string name) |
268 |
{ |
269 |
var val = _parameters[name].AttachedParam.Value; |
270 |
if (val == DBNull.Value) |
271 |
{ |
272 |
if (default(T) != null) |
273 |
throw new ApplicationException("Attempting to cast a DBNull to a non nullable type!"); |
274 |
return default(T); |
275 |
} |
276 |
|
277 |
return (T)val; |
278 |
} |
279 |
|
280 |
|
281 |
public NpgsqlParameter Get(string name) |
282 |
{ |
283 |
return ParamInfoToNpgParam(_parameters[name]); |
284 |
} |
285 |
|
286 |
private class ParamInfo |
287 |
{ |
288 |
public string Name { get; set; } |
289 |
public object Value { get; set; } |
290 |
public ParameterDirection ParameterDirection { get; set; } |
291 |
public DbType? DbType { get; set; } |
292 |
|
293 |
public NpgsqlTypes.NpgsqlDbType? NpgsqlType { get; set; } |
294 |
public int? Size { get; set; } |
295 |
public IDbDataParameter AttachedParam { get; set; } |
296 |
internal Action<object, DynamicParameters> OutputCallback { get; set; } |
297 |
internal object OutputTarget { get; set; } |
298 |
internal bool CameFromTemplate { get; set; } |
299 |
|
300 |
public byte? Precision { get; set; } |
301 |
public byte? Scale { get; set; } |
302 |
} |
303 |
} |
304 |
} |