프로젝트

일반

사용자정보

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

markus / ConvertService / ServiceBase / Markus.Service.DataBase.Dapper / MixParameters.cs @ 5532bcc0

이력 | 보기 | 이력해설 | 다운로드 (10.8 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 = param.Name.ToLower();
90

    
91
                if (command.CommandType == CommandType.StoredProcedure)
92
                    name = Clean(param.Name);
93

    
94
                 var isCustomQueryParameter = val is SqlMapper.ICustomQueryParameter;
95

    
96
                SqlMapper.ITypeHandler handler = null;
97
                if (dbType == null && val != null && !isCustomQueryParameter)
98
                {
99
#pragma warning disable 618
100
                    dbType = SqlMapper.LookupDbType(val.GetType(), name, true, out handler);
101
#pragma warning disable 618
102
                }
103
                if (isCustomQueryParameter)
104
                {
105
                    ((SqlMapper.ICustomQueryParameter)val).AddParameter(command, name);
106
                }
107
                else if (dbType == EnumerableMultiParameter)
108
                {
109
#pragma warning disable 612, 618
110
                    SqlMapper.PackListParameters(command, name, val);
111
#pragma warning restore 612, 618
112
                }
113
                else
114
                {
115
                    bool add = !command.Parameters.Contains(name);
116
                    IDbDataParameter p;
117
                    if (add)
118
                    {
119
                        p = command.CreateParameter();
120
                        p.ParameterName = name;
121
                    }
122
                    else
123
                    {
124
                        p = (IDbDataParameter)command.Parameters[name];
125
                    }
126

    
127
                    p.Direction = param.ParameterDirection;
128
                    if (handler == null)
129
                    {
130
#pragma warning disable 0618
131
                        p.Value = SqlMapper.SanitizeParameterValue(val);
132
#pragma warning restore 0618
133
                        if (ShouldSetDbType(dbType) && p.DbType != dbType.GetValueOrDefault())
134
                        {
135
                            p.DbType = dbType.GetValueOrDefault();
136
                        }
137
                        var s = val as string;
138
                        if (s?.Length <= DbString.DefaultLength)
139
                        {
140
                            p.Size = DbString.DefaultLength;
141
                        }
142
                        if (param.Size != null) p.Size = param.Size.Value;
143
                        if (param.Precision != null) p.Precision = param.Precision.Value;
144
                        if (param.Scale != null) p.Scale = param.Scale.Value;
145
                    }
146
                    else
147
                    {
148
                        if (ShouldSetDbType(dbType)) p.DbType = dbType.GetValueOrDefault();
149
                        if (param.Size != null) p.Size = param.Size.Value;
150
                        if (param.Precision != null) p.Precision = param.Precision.Value;
151
                        if (param.Scale != null) p.Scale = param.Scale.Value;
152
                        handler.SetValue(p, val ?? DBNull.Value);
153
                    }
154

    
155
                    if (add)
156
                    {
157
                        command.Parameters.Add(p);
158
                    }
159
                    param.AttachedParam = p;
160
                }
161
            }
162

    
163
            // note: most non-privileged implementations would use: this.ReplaceLiterals(command);
164
            //if (literals.Count != 0) SqlMapper.ReplaceLiterals(this, command);
165
        }
166

    
167
        private void npgAddParamaters(IDbCommand command, SqlMapper.Identity identity)
168
        { 
169
            foreach (var param in _parameters.Values)
170
            {
171
                if (((NpgsqlCommand)command).Parameters.Contains(param.Name))
172
                {
173
                    ((NpgsqlCommand)command).Parameters.Remove(param.Name);
174
                }
175

    
176
                var p = ParamInfoToNpgParam(param);
177
                p.ParameterName = param.Name;
178

    
179
                command.Parameters.Add(p);
180

    
181
                param.AttachedParam = p;
182
            }
183
        }
184

    
185
        private NpgsqlParameter ParamInfoToNpgParam(ParamInfo param)
186
        {
187
            NpgsqlParameter p = new NpgsqlParameter();
188

    
189
            var val = param.Value;
190
            p.Value = val ?? DBNull.Value;
191
            p.Direction = param.ParameterDirection;
192
            if (param.Size != null) p.Size = param.Size.Value;
193
            if (param.NpgsqlType != null)
194
            {
195
                p.NpgsqlDbType = param.NpgsqlType.Value;
196
            }
197
            else if (param.Value != null)
198
            {
199
                var npgType = dbTypeConvert.GetNpgsqlDbType(param.Value.GetType()).Value;
200

    
201
                if (npgType == NpgsqlDbType.Text)
202
                {
203
                    //npgType = NpgsqlDbType.Varchar;
204
                }
205

    
206
                p.NpgsqlDbType = npgType;
207
            }
208
            else if (param.DbType != null)
209
            {
210
                var npgType = dbTypeConvert.GetNpgsqlDbType(param.DbType.Value).Value;
211

    
212
                if (npgType == NpgsqlDbType.Text)
213
                {
214
                    //npgType = NpgsqlDbType.Varchar;
215
                }
216

    
217
                p.NpgsqlDbType = npgType;
218
            }
219
            else
220
            {
221
                throw new Exception($"{param.Name} npgSQL type을 알 수 없습니다.");
222
            }
223

    
224
            return p;
225
        }
226

    
227
        private static string Clean(string name)
228
        {
229
            if (!string.IsNullOrEmpty(name))
230
            {
231
                switch (name[0])
232
                {
233
                    case '@':
234
                    case ':':
235
                    case '?':
236
                        return name.Substring(1);
237
                }
238
            }
239
            return name;
240
        }
241
        internal void Add(string name,object value = null,NpgsqlTypes.NpgsqlDbType? npgsqlDbType = null, DbType? dbType = null, ParameterDirection? direction = null, int? size = null)
242
        {
243
            if(DBMS == DBMSType.MSSQL)
244
            {
245
                switch (direction)
246
                {
247
                    case ParameterDirection.Output:
248
                    case ParameterDirection.InputOutput:
249
                        if(size == null)
250
                        {
251
                            size = 50;
252
                            //throw new Exception($"{name}는 MSSQL인 경우 direction이 {direction.ToString()}이므로 size를 지정하여야 합니다.");
253
                        }
254
                    break;
255
                    default:
256
                        break;
257
                }
258
            }
259

    
260
            _parameters[Clean(name)] = new ParamInfo
261
            {
262
                Name = name,
263
                Value = value,
264
                ParameterDirection = direction ?? ParameterDirection.Input,
265
                DbType = dbType,
266
                NpgsqlType = npgsqlDbType,
267
                Size = size
268
            };
269
        }
270

    
271
        internal T Get<T>(string name)
272
        {
273
            var val = _parameters[name].AttachedParam.Value;
274
            if (val == DBNull.Value)
275
            {
276
                if (default(T) != null)
277
                    throw new ApplicationException("Attempting to cast a DBNull to a non nullable type!");
278
                return default(T);
279
            }
280

    
281
            return (T)val;
282
        }
283

    
284

    
285
        public NpgsqlParameter Get(string name)
286
        {
287
            return ParamInfoToNpgParam(_parameters[name]);
288
        }
289

    
290
        private class ParamInfo
291
        {
292
            public string Name { get; set; }
293
            public object Value { get; set; }
294
            public ParameterDirection ParameterDirection { get; set; }
295
            public DbType? DbType { get; set; }
296

    
297
            public NpgsqlTypes.NpgsqlDbType? NpgsqlType { get; set; }
298
            public int? Size { get; set; }
299
            public IDbDataParameter AttachedParam { get; set; }
300
            internal Action<object, DynamicParameters> OutputCallback { get; set; }
301
            internal object OutputTarget { get; set; }
302
            internal bool CameFromTemplate { get; set; }
303

    
304
            public byte? Precision { get; set; }
305
            public byte? Scale { get; set; }
306
        }
307
    }
308
}
클립보드 이미지 추가 (최대 크기: 500 MB)