Mercurial > pub > bltoolkit
diff Source/Data/DataProvider/AccessDataProvider.cs @ 0:f990fcb411a9
Копия текущей версии из github
author | cin |
---|---|
date | Thu, 27 Mar 2014 21:46:09 +0400 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Source/Data/DataProvider/AccessDataProvider.cs Thu Mar 27 21:46:09 2014 +0400 @@ -0,0 +1,298 @@ +using System; +using System.Data; +using System.Data.OleDb; +using System.Text.RegularExpressions; + +namespace BLToolkit.Data.DataProvider +{ + using Mapping; + using Sql.SqlProvider; + + public class AccessDataProvider : OleDbDataProvider + { + private static Regex _paramsExp; + + // Based on idea from http://qapi.blogspot.com/2006/12/deriveparameters-oledbprovider-ii.html + // + public override bool DeriveParameters(IDbCommand command) + { + if (command == null) + throw new ArgumentNullException("command"); + + if (command.CommandType != CommandType.StoredProcedure) + throw new InvalidOperationException("command.CommandType must be CommandType.StoredProcedure"); + + var conn = command.Connection as OleDbConnection; + + if (conn == null || conn.State != ConnectionState.Open) + throw new InvalidOperationException("Invalid connection state."); + + command.Parameters.Clear(); + + var dt = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Procedures, new object[]{null, null, command.CommandText}); + + if (dt.Rows.Count == 0) + { + // Jet does convert parameretless procedures to views. + // + dt = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Views, new object[]{null, null, command.CommandText}); + + if (dt.Rows.Count == 0) + throw new DataException(string.Format("Stored procedure '{0}' not found", command.CommandText)); + + // Do nothing. There is no parameters. + // + } + else + { + var col = dt.Columns["PROCEDURE_DEFINITION"]; + + if (col == null) + { + // Not really possible + // + return false; + } + + if (_paramsExp == null) + _paramsExp = new Regex(@"PARAMETERS ((\[(?<name>[^\]]+)\]|(?<name>[^\s]+))\s(?<type>[^,;\s]+(\s\([^\)]+\))?)[,;]\s)*", RegexOptions.Compiled | RegexOptions.ExplicitCapture); + + var match = _paramsExp.Match((string)dt.Rows[0][col.Ordinal]); + var names = match.Groups["name"].Captures; + var types = match.Groups["type"].Captures; + + if (names.Count != types.Count) + { + // Not really possible + // + return false; + } + + var separators = new[] {' ', '(', ',', ')'}; + + for (var i = 0; i < names.Count; ++i) + { + var paramName = names[i].Value; + var rawType = types[i].Value.Split(separators, StringSplitOptions.RemoveEmptyEntries); + var p = new OleDbParameter(paramName, GetOleDbType(rawType[0])); + + if (rawType.Length > 2) + { + p.Precision = Common.Convert.ToByte(rawType[1]); + p.Scale = Common.Convert.ToByte(rawType[2]); + } + else if (rawType.Length > 1) + { + p.Size = Common.Convert.ToInt32(rawType[1]); + } + + command.Parameters.Add(p); + } + } + + return true; + } + + private static OleDbType GetOleDbType(string jetType) + { + switch (jetType.ToLower()) + { + case "byte": + case "tinyint": + case "integer1": + return OleDbType.TinyInt; + + case "short": + case "smallint": + case "integer2": + return OleDbType.SmallInt; + + case "int": + case "integer": + case "long": + case "integer4": + case "counter": + case "identity": + case "autoincrement": + return OleDbType.Integer; + + case "single": + case "real": + case "float4": + case "ieeesingle": + return OleDbType.Single; + + + case "double": + case "number": + case "double precision": + case "float": + case "float8": + case "ieeedouble": + return OleDbType.Double; + + case "currency": + case "money": + return OleDbType.Currency; + + case "dec": + case "decimal": + case "numeric": + return OleDbType.Decimal; + + case "bit": + case "yesno": + case "logical": + case "logical1": + return OleDbType.Boolean; + + case "datetime": + case "date": + case "time": + return OleDbType.Date; + + case "alphanumeric": + case "char": + case "character": + case "character varying": + case "national char": + case "national char varying": + case "national character": + case "national character varying": + case "nchar": + case "string": + case "text": + case "varchar": + return OleDbType.VarWChar; + + case "longchar": + case "longtext": + case "memo": + case "note": + case "ntext": + return OleDbType.LongVarWChar; + + case "binary": + case "varbinary": + case "binary varying": + case "bit varying": + return OleDbType.VarBinary; + + case "longbinary": + case "image": + case "general": + case "oleobject": + return OleDbType.LongVarBinary; + + case "guid": + case "uniqueidentifier": + return OleDbType.Guid; + + default: + // Each release of Jet brings many new aliases to existing types. + // This list may be outdated, please send a report to us. + // + throw new NotSupportedException("Unknown DB type '" + jetType + "'"); + } + } + + public override void AttachParameter(IDbCommand command, IDbDataParameter parameter) + { + // Do some magic to workaround 'Data type mismatch in criteria expression' error + // in JET for some european locales. + // + if (parameter.Value is DateTime) + { + // OleDbType.DBTimeStamp is locale aware, OleDbType.Date is locale neutral. + // + ((OleDbParameter)parameter).OleDbType = OleDbType.Date; + } + else if (parameter.Value is decimal) + { + // OleDbType.Decimal is locale aware, OleDbType.Currency is locale neutral. + // + ((OleDbParameter)parameter).OleDbType = OleDbType.Currency; + } + + base.AttachParameter(command, parameter); + } + + public new const string NameString = DataProvider.ProviderName.Access; + + public override string Name + { + get { return NameString; } + } + + public override int MaxBatchSize + { + get { return 0; } + } + + public override ISqlProvider CreateSqlProvider() + { + return new AccessSqlProvider(); + } + + public override object Convert(object value, ConvertType convertType) + { + switch (convertType) + { + case ConvertType.ExceptionToErrorNumber: + if (value is OleDbException) + { + var ex = (OleDbException)value; + if (ex.Errors.Count > 0) + return ex.Errors[0].NativeError; + } + + break; + } + + return SqlProvider.Convert(value, convertType); + } + + #region DataReaderEx + + public override IDataReader GetDataReader(MappingSchema schema, IDataReader dataReader) + { + return dataReader is OleDbDataReader? + new DataReaderEx((OleDbDataReader)dataReader): + base.GetDataReader(schema, dataReader); + } + + class DataReaderEx : DataReaderBase<OleDbDataReader>, IDataReader + { + public DataReaderEx(OleDbDataReader rd): base(rd) + { + } + + public new object GetValue(int i) + { + var value = DataReader.GetValue(i); + + if (value is DateTime) + { + var dt = (DateTime)value; + + if (dt.Year == 1899 && dt.Month == 12 && dt.Day == 30) + return new DateTime(1, 1, 1, dt.Hour, dt.Minute, dt.Second, dt.Millisecond); + } + + return value; + } + + public new DateTime GetDateTime(int i) + { + var dt = DataReader.GetDateTime(i); + + if (dt.Year == 1899 && dt.Month == 12 && dt.Day == 30) + return new DateTime(1, 1, 1, dt.Hour, dt.Minute, dt.Second, dt.Millisecond); + + return dt; + } + } + + #endregion + } +}