/// <summary> /// 使用指定的连接字符串和<see cref="DbProviderFactory"/>实例初始化<see cref="DbClient"/>的新实例。 /// </summary> /// <param name="connectionString">连接字符串。</param> /// <param name="factory"><see cref="DbProviderFactory"/>实例</param> public DbClient(string connectionString, DbProviderFactory factory) { ArgAssert.NotNull(factory, nameof(factory)); ArgAssert.NotNullOrEmptyOrWhitespace(connectionString, nameof(connectionString)); _factory = factory; ConnectionString = connectionString; }
private ThreadLocalTransactionKeeper(DbProviderFactory dbProviderFactory, string connectionString) { ArgAssert.NotNull(dbProviderFactory, "dbProviderFactory"); ArgAssert.NotNullOrEmptyOrWhitespace(connectionString, "connectionString"); _factory = dbProviderFactory; _connectionString = connectionString; }
/// <summary> /// 使用指定的连接字符串和<see cref="DbProviderFactory"/>工厂初始化<see cref="DbClient"/>的新实例。 /// </summary> /// <param name="connectionString">连接字符串。</param> /// <param name="factoryGetter">用于创建<see cref="DbProviderFactory"/>。</param> public DbClient(string connectionString, Func <DbProviderFactory> factoryGetter) { ArgAssert.NotNull(factoryGetter, nameof(factoryGetter)); ArgAssert.NotNullOrEmptyOrWhitespace(connectionString, nameof(connectionString)); _factoryGetter = factoryGetter; ConnectionString = connectionString; }
public override int GetValues(object[] values) { ArgAssert.NotNull(values, nameof(values)); var num = Math.Min(values.Length, _fieldCount); Array.Copy(_values, values, num); return(num); }
/// <summary> /// 从给定的类型上解析泛型参数表,并指定解析参数时所使用的泛型类型定义。 /// </summary> /// <param name="type">从此类型上解析泛型参数表。</param> /// <param name="genericTypeDefinition">泛型类型定义。可以是接口,也可以是非接口类型。</param> /// <returns>类型的泛型参数的数组,其元素顺序与类型定义的顺序一致。</returns> /// <exception cref="ArgumentNullException"><paramref name="type"/>为<c>null</c>。</exception> /// <exception cref="ArgumentNullException"><paramref name="genericTypeDefinition"/>为<c>null</c>。</exception> /// <exception cref="ArgumentException"><paramref name="genericTypeDefinition"/>不是泛型类型定义。</exception> /// <example> /// 一个类型可以继承多个泛型类型,例如: /// GenericClass{T} : IDictionary{T, int}, ICollection{string} /// 此时,对于GenericClass{long},使用泛型定义IDictionary{,},获取参数表类型是 [long, int]; /// 而对于泛型定义ICollection{}则结果是 [string]; /// </example> public static Type[] GetGenericArguments(Type type, Type genericTypeDefinition) { ArgAssert.NotNull(type, "type"); ArgAssert.NotNull(genericTypeDefinition, "genericTypeDefinition"); if (!genericTypeDefinition.IsGenericTypeDefinition) { var msg = string.Format( "The type {0} is not a generic type definition.", genericTypeDefinition.Name); throw new ArgumentException(msg, "genericTypeDefinition"); } if (genericTypeDefinition.IsInterface) { if (type.IsGenericType && type.GetGenericTypeDefinition() == genericTypeDefinition) { return(type.GetGenericArguments()); } foreach (var interfaceType in type.GetInterfaces()) { if (!interfaceType.IsGenericType) { continue; } if (interfaceType.GetGenericTypeDefinition() != genericTypeDefinition) { continue; } return(interfaceType.GetGenericArguments()); } } else { var baseType = type; do { if (!baseType.IsGenericType) { continue; } if (baseType.GetGenericTypeDefinition() != genericTypeDefinition) { continue; } return(baseType.GetGenericArguments()); } while ((baseType = baseType.BaseType) != null); } return(null); }
/// <summary> /// 创建<see cref="ThreadLocalTransactionKeeper"/>的新实例。 /// </summary> /// <param name="dbProviderFactory"><see cref="DbProviderFactory"/>实例。</param> /// <param name="connectionString">初始化数据库连接的连接字符串。</param> /// <param name="commandTimeout"> /// 指定事务内的命令的默认执行超时时间,当方法没有单独制定超时时,套用此超时值。 /// </param> public ThreadLocalTransactionKeeper( DbProviderFactory dbProviderFactory, string connectionString, int commandTimeout) { ArgAssert.NotNull(dbProviderFactory, nameof(dbProviderFactory)); ArgAssert.NotNullOrEmptyOrWhitespace(connectionString, nameof(connectionString)); Factory = dbProviderFactory; ConnectionString = connectionString; DefaultTimeout = commandTimeout; }
public override int GetValues(object[] values) { ArgAssert.NotNull(values, "values"); var itemArray = _currentRow.ItemArray; var len = Math.Min(itemArray.Length, values.Length); Array.Copy(itemArray, values, len); return(len); }
/// <summary> /// 返回查询语句对应查询结果的<see cref="System.Data.DataSet"/>。 /// </summary> /// <param name="sql">查询SQL。</param> /// <param name="parameters">参数序列。空序列或null表示没有参数。</param> /// <param name="commandType">命令的类型。</param> /// <param name="timeout">命令的超时时间,单位毫秒。0为不指定。</param> /// <returns>表示查询结果的<see cref="System.Data.DataSet"/>。</returns> /// <exception cref="ArgumentNullException">当<paramref name="sql"/>为<c>null</c>。</exception> /// <exception cref="ArgumentException">当<paramref name="sql"/>长度为0。</exception> public DataSet DataSet(string sql, IEnumerable <DbParameter> parameters = null, CommandType commandType = CommandType.Text, int timeout = 0) { ArgAssert.NotNullOrEmpty(sql, "sql"); var ds = new DataSet(); FillDataSet(ds, sql, parameters, commandType, timeout); return(ds); }
public TransactionScopeTransactionKeeper(DbProviderFactory dbProviderFactory, string connectionString) { ArgAssert.NotNull(dbProviderFactory, "dbProviderFactory"); ArgAssert.NotNullOrEmptyOrWhitespace(connectionString, "connectionString"); _factory = dbProviderFactory; _connectionString = connectionString; //鉴于应用场景,直接开启事务控制(不过数据库连接还没初始化) _tran = new TransactionScope(); }
/// <summary> /// 初始化类型的新实例。 /// </summary> /// <param name="dbProviderFactory"><see cref="DbProviderFactory"/>的实例。</param> /// <param name="connectionString">指定数据库的连接字符串。</param> /// <param name="commandTimeout"> /// 指定事务内的命令的默认执行超时时间,当方法没有单独制定超时时,套用此超时值。 /// </param> public TransactionScopeTransactionKeeper( DbProviderFactory dbProviderFactory, string connectionString, int commandTimeout) { ArgAssert.NotNull(dbProviderFactory, "dbProviderFactory"); ArgAssert.NotNullOrEmptyOrWhitespace(connectionString, "connectionString"); Factory = dbProviderFactory; ConnectionString = connectionString; DefaultTimeout = commandTimeout; //鉴于应用场景,直接开启事务控制(不过数据库连接还没初始化) _tran = new TransactionScope(); }
public virtual int GetValues(object[] values) { ArgAssert.NotNull(values, "values"); var num = Math.Min(values.Length, FieldCount); for (int i = 0; i <= num; i++) { values[i] = GetValue(i); } return(num); }
/// <summary> /// 获取查询结果得行序列。 /// </summary> /// <param name="sql">查询SQL。</param> /// <param name="parameters">参数序列。空序列或null表示没有参数。</param> /// <param name="commandType">命令的类型。</param> /// <param name="timeout">命令的超时时间,单位毫秒。0为不指定。</param> /// <returns>查询结果得行序列。</returns> public IEnumerable <IDataRecord> Rows(string sql, IEnumerable <DbParameter> parameters = null, CommandType commandType = CommandType.Text, int timeout = 0) { ArgAssert.NotNullOrEmpty(sql, "sql"); DbConnection connection = null; DbDataReader reader = null; DbCommand cmd; try { connection = CreateAndOpenConnection(); cmd = CreateCommand(sql, connection, parameters, commandType, timeout); reader = cmd.ExecuteReader(); } catch (Exception ex) { throw new SqlExecutingException(sql, commandType, parameters, ex); } finally { //获取reader失败时,关闭连接 if (reader == null && connection != null) { CloseConnection(connection); } } try { cmd.Parameters.Clear(); while (reader.Read()) { yield return(reader); } } finally { if (!reader.IsClosed) { reader.Close(); } if (connection != null) { CloseConnection(connection); } } }
public object[] MapRow(IDataRecord record, int rowNum) { ArgAssert.NotNull(record, nameof(record)); var len = record.FieldCount; var array = new object[len]; for (int i = 0; i < len; i++) { array[i] = record[i]; } return(array); }
/// <summary> /// 使用<see cref="IMapper{T}"/>查询指定对象的集合。 /// </summary> /// <typeparam name="T">查询的目标类型。</typeparam> /// <param name="mapper"><see cref="IMapper{T}"/>的实例。</param> /// <param name="sql">查询SQL。</param> /// <param name="parameters">参数序列。空序列或null表示没有参数。</param> /// <param name="commandType">命令的类型。</param> /// <param name="timeout">命令的超时时间,单位毫秒。0为不指定。</param> /// <returns>目标类型的实例的集合。若查询命中的行数为0,返回空集合。</returns> public IList <T> List <T>(IMapper <T> mapper, string sql, IEnumerable <DbParameter> parameters = null, CommandType commandType = CommandType.Text, int timeout = 0) { ArgAssert.NotNullOrEmpty(sql, "sql"); ArgAssert.NotNull(mapper, "mapper"); var results = new List <T>(); DbConnection connection = null; DbCommand cmd = null; IDataReader reader = null; try { connection = CreateAndOpenConnection(); cmd = CreateCommand(sql, connection, parameters, commandType, timeout); reader = cmd.ExecuteReader(); var rowCount = 0; while (reader.Read()) { var row = mapper.MapRow(reader, ++rowCount); results.Add(row); } } catch (Exception ex) { throw new SqlExecutingException(sql, commandType, parameters, ex); } finally { if (cmd != null) { cmd.Parameters.Clear(); } if (reader != null && !reader.IsClosed) { reader.Close(); } if (connection != null) { CloseConnection(connection); } } return(results); }
/// <summary> /// 使用<see cref="IMapper{T}"/>查询指定对象。 /// SQL命中的记录必须为1行,否则抛出异常。 /// </summary> /// <typeparam name="T">查询的目标类型。</typeparam> /// <param name="mapper"><see cref="IMapper{T}"/>的实例。</param> /// <param name="sql">查询SQL。</param> /// <param name="parameters">参数序列。空序列或null表示没有参数。</param> /// <param name="commandType">命令的类型。</param> /// <param name="timeout">命令的超时时间,单位毫秒。0表示不指定,此时套用默认的超时设置。</param> /// <returns>目标类型的实例。</returns> /// <exception cref="IncorrectResultSizeException">当SQL命中的记录行数不为 1。</exception> public virtual T ForceGet <T>(IMapper <T> mapper, string sql, IEnumerable <DbParameter> parameters = null, CommandType commandType = CommandType.Text, int timeout = 0) { ArgAssert.NotNullOrEmpty(sql, nameof(sql)); ArgAssert.NotNull(mapper, nameof(mapper)); DbConnection connection = null; IDataReader reader = null; DbCommand cmd = null; try { connection = CreateAndOpenConnection(); cmd = CreateCommand(sql, connection, parameters, commandType, timeout); reader = cmd.ExecuteReader(); int rowCount; T result; if (DbClientHelper.TryMapUniqueRow(reader, mapper, out result, out rowCount)) { return(result); } throw new IncorrectResultSizeException(sql, CommandType.Text, parameters, 1, rowCount); } catch (Exception ex) { throw new SqlExecutingException(sql, commandType, parameters, ex); } finally { cmd?.Parameters.Clear(); if (reader != null && !reader.IsClosed) { reader.Close(); } if (connection != null) { CloseConnection(connection); } } }
/// <summary> /// 使用<see cref="IMapper{T}"/>查询指定对象的集合。 /// 若查询未命中纪录,返回空集(长度为0,不是null)。 /// 这是一个异步操作。 /// </summary> /// <typeparam name="T">查询的目标类型。</typeparam> /// <param name="mapper"><see cref="IMapper{T}"/>的实例。</param> /// <param name="sql">查询SQL。</param> /// <param name="parameters">参数序列。空序列或null表示没有参数。</param> /// <param name="commandType">命令的类型。</param> /// <param name="timeout">命令的超时时间,单位毫秒。0表示不指定,此时套用默认的超时设置。</param> /// <returns>目标类型的实例的集合。若查询命中的行数为0,返回空集合。</returns> public virtual async Task <IList <T> > ListAsync <T>(IMapper <T> mapper, string sql, IEnumerable <DbParameter> parameters = null, CommandType commandType = CommandType.Text, int timeout = 0) { if (!AsyncEnabled) { return(List(mapper, sql, parameters, commandType, timeout)); } ArgAssert.NotNullOrEmpty(sql, nameof(sql)); ArgAssert.NotNull(mapper, nameof(mapper)); DbConnection connection = null; DbCommand cmd = null; IDataReader reader = null; try { connection = await CreateAndOpenConnectionAsync(); cmd = CreateCommand(sql, connection, parameters, commandType, timeout); reader = await cmd.ExecuteReaderAsync(); return(MapRowsToList(reader, mapper)); } catch (Exception ex) { throw new SqlExecutingException(sql, commandType, parameters, ex); } finally { cmd?.Parameters.Clear(); if (reader != null && !reader.IsClosed) { reader.Close(); } if (connection != null) { CloseConnection(connection); } } }
/// <summary> /// 初始化<see cref="SingleRowKeeper"/>的新实例,并制定提供记录数据的<see cref="IDataRecord"/>。 /// </summary> /// <param name="dataRecord"> /// <see cref="IDataRecord"/>的实例,其第一行数据将被记录下来。 /// </param> public SingleRowKeeper(IDataRecord dataRecord) { ArgAssert.NotNull(dataRecord, nameof(dataRecord)); var fieldCount = dataRecord.FieldCount; _fieldCount = fieldCount; // keep meta data & values _values = new object[fieldCount]; _fieldTypes = new Type[fieldCount]; _columnNames = new string[fieldCount]; for (int i = 0; i < fieldCount; i++) { _values[i] = dataRecord.GetValue(i); _fieldTypes[i] = dataRecord.GetFieldType(i); _columnNames[i] = dataRecord.GetName(i); } }
/// <summary> /// 判断给定的类型是否是匿名类型。 /// </summary> /// <param name="type">待判断的类型。</param> /// <returns>true若给定的类型是匿名类型;否则为false。</returns> public static bool IsAnonymousType(Type type) { ArgAssert.NotNull(type, "type"); if (!type.IsGenericType) { return(false); } if (!Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute), false)) { return(false); } if ((type.Attributes & TypeAttributes.NotPublic) != TypeAttributes.NotPublic) { return(false); } return(type.Name.Contains("AnonymousType")); }
/// <summary> /// 返回查询语句对应查询结果的<see cref="System.Data.DataTable"/>。 /// 这是一个异步操作。 /// </summary> /// <param name="sql">查询SQL。</param> /// <param name="parameters">参数序列。空序列或null表示没有参数。</param> /// <param name="commandType">命令的类型。</param> /// <param name="timeout">命令的超时时间,单位毫秒。0表示不指定,此时套用默认的超时设置。</param> /// <returns>表示查询结果的<see cref="System.Data.DataTable"/>。</returns> /// <exception cref="ArgumentNullException">当<paramref name="sql"/>为<c>null</c>。</exception> /// <exception cref="ArgumentException">当<paramref name="sql"/>长度为0。</exception> public virtual async Task <DataTable> DataTableAsync(string sql, IEnumerable <DbParameter> parameters = null, CommandType commandType = CommandType.Text, int timeout = 0) { if (!AsyncEnabled) { return(DataTable(sql, parameters, commandType, timeout)); } ArgAssert.NotNullOrEmpty(sql, nameof(sql)); DbConnection connection = null; DbCommand cmd = null; try { connection = await CreateAndOpenConnectionAsync(); cmd = CreateCommand(sql, connection, parameters, commandType, timeout); // TODO 目前还没有找到适当的异步填充 DataTable 的方法,填充部分目前以非异步方式执行。 // dataTable.Load(reader) 在 mysql 的部分类型字段(比如longtext)将出现异常,必须通过 mysql // 的 connector library 提供的 MySqlDataAdapter 填充,解决方案尚不清晰。 return(FillDataTable(cmd)); } catch (Exception ex) { throw new SqlExecutingException(sql, commandType, parameters, ex); } finally { cmd?.Parameters.Clear(); if (connection != null) { CloseConnection(connection); } } }
/// <summary> /// 获取查询结果得行序列。 /// 这是一个异步操作。 /// </summary> /// <param name="sql">查询SQL。</param> /// <param name="parameters">参数序列。空序列或null表示没有参数。</param> /// <param name="commandType">命令的类型。</param> /// <param name="timeout">命令的超时时间,单位毫秒。0表示不指定,此时套用默认的超时设置。</param> /// <returns>查询结果得行序列。</returns> public virtual async Task <IEnumerable <IDataRecord> > RowsAsync(string sql, IEnumerable <DbParameter> parameters = null, CommandType commandType = CommandType.Text, int timeout = 0) { if (!AsyncEnabled) { return(Rows(sql, parameters, commandType, timeout)); } ArgAssert.NotNullOrEmpty(sql, nameof(sql)); DbConnection connection = null; DbDataReader reader = null; DbCommand cmd = null; try { connection = await CreateAndOpenConnectionAsync(); cmd = CreateCommand(sql, connection, parameters, commandType, timeout); reader = await cmd.ExecuteReaderAsync(); } catch (Exception ex) { throw new SqlExecutingException(sql, commandType, parameters, ex); } finally { cmd?.Parameters.Clear(); //获取reader失败时,关闭连接 if (reader == null && connection != null) { CloseConnection(connection); } } return(YieldRows(connection, reader)); }
/// <summary> /// 返回查询语句对应查询结果的<see cref="System.Data.DataSet"/>。 /// 这是一个异步操作。 /// </summary> /// <param name="sql">查询SQL。</param> /// <param name="parameters">参数序列。空序列或null表示没有参数。</param> /// <param name="commandType">命令的类型。</param> /// <param name="timeout">命令的超时时间,单位毫秒。0表示不指定,此时套用默认的超时设置。</param> /// <returns>表示查询结果的<see cref="System.Data.DataSet"/>。</returns> /// <exception cref="ArgumentNullException">当<paramref name="sql"/>为<c>null</c>。</exception> /// <exception cref="ArgumentException">当<paramref name="sql"/>长度为0。</exception> public virtual async Task <DataSet> DataSetAsync(string sql, IEnumerable <DbParameter> parameters = null, CommandType commandType = CommandType.Text, int timeout = 0) { if (!AsyncEnabled) { return(DataSet(sql, parameters, commandType, timeout)); } ArgAssert.NotNullOrEmpty(sql, nameof(sql)); DbConnection connection = null; DbCommand cmd = null; try { connection = await CreateAndOpenConnectionAsync(); cmd = CreateCommand(sql, connection, parameters, commandType, timeout); // TODO 目前还没有找到适当的异步填充 DataSet 的方法,填充部分目前以非异步方式执行。 // 主要因为 DbDataAdaper 没有提供异步的方法,而如何从 IDataReader 获得 DataSet还没搞清楚。 return(FillDataSet(cmd)); } catch (Exception ex) { throw new SqlExecutingException(sql, commandType, parameters, ex); } finally { cmd?.Parameters.Clear(); if (connection != null) { CloseConnection(connection); } } }
/// <summary> /// 使用<see cref="IMapper{T}"/>查询指定对象。 /// 若满足条件的记录不存在,返回目标类型的默认值(对于引用类型为<c>null</c>)。 /// </summary> /// <typeparam name="T">查询的目标类型。</typeparam> /// <param name="sql">查询SQL。</param> /// <param name="parameters">参数序列。空序列或null表示没有参数。</param> /// <param name="commandType">命令的类型。</param> /// <param name="timeout">命令的超时时间,单位毫秒。0表示不指定,此时套用默认的超时设置。</param> /// <param name="mapper"><see cref="IMapper{T}"/>的实例。</param> /// <returns>目标类型的实例。</returns> public virtual T Get <T>(IMapper <T> mapper, string sql, IEnumerable <DbParameter> parameters = null, CommandType commandType = CommandType.Text, int timeout = 0) { ArgAssert.NotNullOrEmpty(sql, nameof(sql)); ArgAssert.NotNull(mapper, nameof(mapper)); DbConnection connection = null; IDataReader reader = null; DbCommand cmd = null; try { connection = CreateAndOpenConnection(); cmd = CreateCommand(sql, connection, parameters, commandType, timeout); reader = cmd.ExecuteReader(); return(reader.Read() ? mapper.MapRow(reader, 1) : default(T)); } catch (Exception ex) { throw new SqlExecutingException(sql, commandType, parameters, ex); } finally { cmd?.Parameters.Clear(); if (reader != null && !reader.IsClosed) { reader.Close(); } if (connection != null) { CloseConnection(connection); } } }
/// <summary> /// 创建类型的新实例。 /// </summary> protected DbProviderFactoryWrapper(DbProviderFactory underlyingProvider) { ArgAssert.NotNull(underlyingProvider, nameof(underlyingProvider)); _underlyingProvider = underlyingProvider; }
/// <summary> /// 使用指定的数据库类型和连接字符串初始化<see cref="SqlDbClient"/>的新实例。 /// </summary> /// <param name="connectionString">连接字符串。</param> public MysqlDbClient(string connectionString) { ArgAssert.NotNullOrEmptyOrWhitespace(connectionString, "connectionString"); ConnectionString = connectionString; }
/// <summary> /// 通过委托定义创建<see cref="IMapper{T}"/>实现。 /// </summary> /// <typeparam name="T">目标类型。</typeparam> /// <param name="rowMapping">从<see cref="IDataRecord"/>获取目标类型的数据的方法。</param> /// <returns><see cref="IMapper{T}"/>的实例。</returns> /// <exception cref="ArgumentNullException">当<paramref name="rowMapping"/>为null。</exception> public static IMapper <T> Custom <T>(Func <IDataRecord, int, T> rowMapping) { ArgAssert.NotNull(rowMapping, "rowMapping"); return(new FunctionMapper <T>(rowMapping)); }
/// <summary> /// 判断给定类型是否是<see cref="System.Nullable{T}"/>的实例。 /// </summary> /// <param name="t">类型。</param> /// <returns>若类型为<see cref="System.Nullable{T}"/>,返回<c>true</c>;否则返回<c>false</c>。</returns> /// <exception cref="ArgumentNullException">当<paramref name="t"/>为<c>null</c>。</exception> public static bool IsNullableType(Type t) { ArgAssert.NotNull(t, "t"); return(t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable <>)); }
/// <summary> /// 判断给定类型是否可被赋值为null。 /// </summary> /// <param name="t">类型。</param> /// <returns>若类型为引用类型,返回<c>true</c>;否则返回<c>false</c>。</returns> /// <exception cref="ArgumentNullException">当<paramref name="t"/>为<c>null</c>。</exception> public static bool IsNullable(Type t) { ArgAssert.NotNull(t, "t"); return(!t.IsValueType || IsNullableType(t)); }
public override Type GetFieldType(int i) { ArgAssert.Between(i, "i", 0, _fieldCount); return(_fieldTypes[i]); }
public override string GetName(int i) { ArgAssert.Between(i, "i", 0, _fieldCount); return(_columnNames[i]); }
public override object GetValue(int i) { ArgAssert.Between(i, "i", 0, _fieldCount); return(_values[i]); }