comparison Source/Data/DataProvider/FdpDataProvider.cs @ 0:f990fcb411a9

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:f990fcb411a9
1 /***
2
3 * FdpDataProvider
4 needed FirebirdClient http://sourceforge.net/project/showfiles.php?group_id=9028&package_id=62107
5 tested with FirebirdClient 2.1.0 Beta 3
6
7 Known troubles:
8 1) Some tests fails due to Fb SQL-syntax specific
9 2) ResultSet mapping doesn't work - not supported by client
10 3) UnitTests.CS.DataAccess.OutRefTest tests: Test2 && TestNullable2 doesnt work:
11 parameters directions should be provided correctly to functions run, that's why
12 output parameterd would be mapped to Entity e, so asserts should be same a in Test1.
13
14 "Features"
15 1) Type conversation due to http://www.firebirdsql.org/manual/migration-mssql-data-types.html
16 BUT! for Binary types BLOB is used! not CHAR!
17 2) InOut parameters faking: InOut parameters are not suppotred by Fb, but they could be
18 emulated: each InOut parameter should be defined in RETURNS() section, and allso has a mirror
19 in parameter section with name [prefix][inOutParameterName], see OutRefTest SP. Faking settings:
20 FdpDataProvider.InOutInputParameterPrefix = "in_";
21 FdpDataProvider.IsInOutParameterEmulation = true;
22 3) Returned values faking. Each parameter with "magic name" woul be treated as ReturnValue.
23 see Scalar_ReturnParameter SP. Faking settings:
24 FdpDataProvider.ReturnParameterName = "RETURN_VALUE";
25 FdpDataProvider.IsReturnValueEmulation = true;
26
27 */
28
29 using System;
30 using System.Collections.Generic;
31 using System.Collections.Specialized;
32 using System.Data;
33 using System.Data.Common;
34 using System.Linq;
35
36 using BLToolkit.Data.Sql.SqlProvider;
37 using BLToolkit.Mapping;
38 using BLToolkit.Reflection;
39
40 using FirebirdSql.Data.FirebirdClient;
41
42 namespace BLToolkit.Data.DataProvider
43 {
44 public class FdpDataProvider : DataProviderBase
45 {
46 public FdpDataProvider()
47 {
48 MappingSchema = new FbMappingSchema();
49 }
50
51 #region InOut & ReturnValue emulation
52 public static string InOutInputParameterPrefix = "in_";
53 public static string ReturnParameterName = "RETURN_VALUE";
54
55 public static bool IsReturnValueEmulation = true;
56 public static bool IsInOutParameterEmulation = true;
57
58 public static bool QuoteIdentifiers
59 {
60 get { return FirebirdSqlProvider.QuoteIdentifiers; }
61 set { FirebirdSqlProvider.QuoteIdentifiers = value; }
62 }
63 #endregion
64
65 #region Overloads
66 public override Type ConnectionType
67 {
68 get { return typeof (FbConnection); }
69 }
70
71 public override string Name
72 {
73 get { return DataProvider.ProviderName.Firebird; }
74 }
75
76 public override int MaxBatchSize
77 {
78 get { return 0; }
79 }
80
81 public override IDbConnection CreateConnectionObject()
82 {
83 return new FbConnection();
84 }
85
86 public override DbDataAdapter CreateDataAdapterObject()
87 {
88 return new FbDataAdapter();
89 }
90
91 public override bool DeriveParameters(IDbCommand command)
92 {
93 if (command is FbCommand)
94 {
95 FbCommandBuilder.DeriveParameters((FbCommand) command);
96
97 if (IsReturnValueEmulation)
98 foreach (IDbDataParameter par in command.Parameters)
99 if (IsReturnValue(par))
100 par.Direction = ParameterDirection.ReturnValue;
101
102 return true;
103 }
104
105 return false;
106 }
107
108 public override object Convert(object value, ConvertType convertType)
109 {
110 switch (convertType)
111 {
112 case ConvertType.ExceptionToErrorNumber:
113 if (value is FbException)
114 {
115 var ex = (FbException) value;
116 if (ex.Errors.Count > 0)
117 foreach (FbError error in ex.Errors)
118 return error.Number;
119 }
120
121 break;
122 }
123
124 return SqlProvider.Convert(value, convertType);
125 }
126
127 public override ISqlProvider CreateSqlProvider()
128 {
129 return new FirebirdSqlProvider();
130 }
131
132 public override bool IsValueParameter(IDbDataParameter parameter)
133 {
134 return parameter.Direction != ParameterDirection.ReturnValue
135 && parameter.Direction != ParameterDirection.Output;
136 }
137
138 private string GetInputParameterName(string ioParameterName)
139 {
140 return (string) Convert(
141 InOutInputParameterPrefix + (string) Convert(ioParameterName, ConvertType.SprocParameterToName),
142 ConvertType.NameToSprocParameter);
143 }
144
145 private static IDbDataParameter GetParameter(string parameterName, IEnumerable<IDbDataParameter> commandParameters)
146 {
147 return commandParameters.FirstOrDefault(par => string.Compare(parameterName, par.ParameterName, true) == 0);
148 }
149
150 private bool IsReturnValue(IDbDataParameter parameter)
151 {
152 if (string.Compare(parameter.ParameterName,
153 (string) Convert(ReturnParameterName, ConvertType.NameToSprocParameter), true) == 0
154 )
155 return true;
156
157 return false;
158 }
159
160 public override void PrepareCommand(ref CommandType commandType, ref string commandText,
161 ref IDbDataParameter[] commandParameters)
162 {
163 if (commandParameters != null)
164 foreach (var par in commandParameters)
165 {
166 if (par.Value is bool)
167 {
168 var value = (bool) par.Value ? "1" : "0";
169
170 par.DbType = DbType.AnsiString;
171 par.Value = value;
172 par.Size = value.Length;
173 }
174 else if (par.Value is Guid)
175 {
176 var value = par.Value.ToString();
177
178 par.DbType = DbType.AnsiStringFixedLength;
179 par.Value = value;
180 par.Size = value.Length;
181 }
182
183 #region "smart" input-output parameter detection
184 if (commandType == CommandType.StoredProcedure && IsInOutParameterEmulation)
185 {
186 var iParameterName = GetInputParameterName(par.ParameterName);
187 var fakeIOParameter = GetParameter(iParameterName, commandParameters);
188
189 if (fakeIOParameter != null)
190 {
191 fakeIOParameter.Value = par.Value;
192
193 // direction should be output, or parameter mistmath for procedure exception
194 // would be thrown
195 par.Direction = ParameterDirection.Output;
196
197 // direction should be Input
198 fakeIOParameter.Direction = ParameterDirection.Input;
199 }
200 }
201 #endregion
202 }
203
204 base.PrepareCommand(ref commandType, ref commandText, ref commandParameters);
205 }
206
207 public override bool InitParameter(IDbDataParameter parameter)
208 {
209 if (parameter.Value is bool)
210 {
211 var value = (bool) parameter.Value ? "1" : "0";
212
213 parameter.DbType = DbType.AnsiString;
214 parameter.Value = value;
215 parameter.Size = value.Length;
216 }
217 else if (parameter.Value is Guid)
218 {
219 var value = parameter.Value.ToString();
220
221 parameter.DbType = DbType.AnsiStringFixedLength;
222 parameter.Value = value;
223 parameter.Size = value.Length;
224 }
225
226 return base.InitParameter(parameter);
227 }
228
229 public override void Configure(NameValueCollection attributes)
230 {
231 var inOutInputParameterPrefix = attributes["InOutInputParameterPrefix"];
232 if (inOutInputParameterPrefix != null)
233 InOutInputParameterPrefix = inOutInputParameterPrefix;
234
235 var returnParameterName = attributes["ReturnParameterName"];
236 if (returnParameterName != null)
237 ReturnParameterName = returnParameterName;
238
239 var isReturnValueEmulation = attributes["IsReturnValueEmulation"];
240 if (isReturnValueEmulation != null)
241 IsReturnValueEmulation = Common.Convert.ToBoolean(isReturnValueEmulation);
242
243 var isInOutParameterEmulation = attributes["IsInOutParameterEmulation"];
244 if (isInOutParameterEmulation != null)
245 IsInOutParameterEmulation = Common.Convert.ToBoolean(isInOutParameterEmulation);
246
247 var quoteIdentifiers = attributes["QuoteIdentifiers"];
248 if (quoteIdentifiers != null)
249 QuoteIdentifiers = Common.Convert.ToBoolean(quoteIdentifiers);
250
251 base.Configure(attributes);
252 }
253 #endregion
254
255 #region FbDataReaderEx
256 public override IDataReader GetDataReader(MappingSchema schema, IDataReader dataReader)
257 {
258 return
259 dataReader is FbDataReader
260 ? new FbDataReaderEx((FbDataReader) dataReader)
261 : base.GetDataReader(schema, dataReader);
262 }
263
264 private class FbDataReaderEx : DataReaderBase<FbDataReader>, IDataReader
265 {
266 public FbDataReaderEx(FbDataReader rd) : base(rd)
267 {
268 }
269
270 #region IDataReader Members
271 public new object GetValue(int i)
272 {
273 var value = DataReader.GetValue(i);
274
275 if (value is DateTime)
276 {
277 var dt = (DateTime) value;
278
279 if (dt.Year == 1970 && dt.Month == 1 && dt.Day == 1)
280 return new DateTime(1, 1, 1, dt.Hour, dt.Minute, dt.Second, dt.Millisecond);
281 }
282
283 return value;
284 }
285
286 public new DateTime GetDateTime(int i)
287 {
288 var dt = DataReader.GetDateTime(i);
289
290 if (dt.Year == 1970 && dt.Month == 1 && dt.Day == 1)
291 return new DateTime(1, 1, 1, dt.Hour, dt.Minute, dt.Second, dt.Millisecond);
292
293 return dt;
294 }
295 #endregion
296 }
297 #endregion
298
299 #region FbMappingSchema
300 public class FbMappingSchema : FirebirdMappingSchema
301 {
302 protected override object MapInternal(InitContext initContext)
303 {
304 var dr = initContext.SourceObject as FbDataReader;
305
306 // Fb's SP returns single row with nulls if selected object doesn't exists
307 // so for all DBNull's (null) should be returned, instead of object instance
308 //
309 if (dr != null)
310 {
311 var i = dr.FieldCount;
312 while (--i >= 0)
313 if (!dr.IsDBNull(i))
314 break;
315
316 // All field are DBNull.
317 //
318 if (i < 0)
319 return null;
320 }
321 return base.MapInternal(initContext);
322 }
323 }
324 #endregion
325 }
326 }