프로젝트

일반

사용자정보

통계
| 브랜치(Branch): | 개정판:

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
}
클립보드 이미지 추가 (최대 크기: 500 MB)