internal static Param[] GetUpdateParameters(object dataEntity, IDictionary <PropertyInfo, ReflectedProperty> propertyMap, int statementId = -1) { var parameters = propertyMap.Values .Where(p => p.IsPersistent && (p.IsSimpleType || p.IsSimpleList) && (p.CanWrite || p.IsAutoGenerated)) .Select(p => new Param { Name = (p.ParameterName.NullIfEmpty() ?? p.PropertyName) + (statementId == -1 ? string.Empty : "_" + statementId), Value = GetParameterValue(dataEntity, p), DbType = Reflector.ClrToDbType(p.PropertyType), Direction = p.Direction, Source = p.MappedColumnName, IsAutoGenerated = p.IsAutoGenerated, IsPrimaryKey = p.IsPrimaryKey }); return(parameters.ToArray()); }
internal static async Task <OperationResponse> ExecuteAsync(string operationText, IEnumerable <Param> parameters, OperationReturnType returnType, OperationType operationType, IList <Type> types = null, string connectionName = null, DbConnection connection = null, DbTransaction transaction = null, bool captureException = false, string schema = null, string connectionStringSection = "ConnectionStrings", IConfiguration config = null) { var rootType = types?[0]; DbConnection dbConnection; var closeConnection = false; if (transaction != null) { dbConnection = transaction.Connection; } else if (connection != null) { dbConnection = connection; } else { dbConnection = DbFactory.CreateConnection(connectionName, rootType, config); closeConnection = true; } if (returnType == OperationReturnType.Guess) { if (operationText.IndexOf("insert", StringComparison.OrdinalIgnoreCase) > -1 || operationText.IndexOf("update", StringComparison.OrdinalIgnoreCase) > -1 || operationText.IndexOf("delete", StringComparison.OrdinalIgnoreCase) > -1) { returnType = OperationReturnType.NonQuery; } else { returnType = OperationReturnType.SingleResult; } } Dictionary <DbParameter, Param> outputParameters = null; var command = dbConnection.CreateCommand(); command.CommandText = operationText; command.CommandType = operationType == OperationType.StoredProcedure ? CommandType.StoredProcedure : CommandType.Text; command.CommandTimeout = 0; if (parameters != null) { ISet <string> parsedParameters = null; if ((config?.IgnoreInvalidParameters).GetValueOrDefault()) { if (operationType == OperationType.StoredProcedure) { parsedParameters = DbFactory.GetProcedureParameters(dbConnection, operationText, true, config); } else { parsedParameters = DbFactory.GetQueryParameters(dbConnection, operationText, true, config); } } foreach (var parameter in parameters) { var name = parameter.Name.TrimStart('@', '?', ':'); if (parsedParameters != null && !parsedParameters.Contains(name)) { continue; } var dbParam = command.CreateParameter(); dbParam.ParameterName = name; dbParam.Direction = parameter.Direction; dbParam.Value = parameter.Value ?? DBNull.Value; if (parameter.Value != null) { if (parameter.Size > -1) { dbParam.Size = parameter.Size; } dbParam.DbType = parameter.DbType ?? Reflector.ClrToDbType(parameter.Type); } else if (parameter.DbType != null) { dbParam.DbType = parameter.DbType.Value; } if (dbParam.Direction == ParameterDirection.Output) { if (outputParameters == null) { outputParameters = new Dictionary <DbParameter, Param>(); } outputParameters.Add(dbParam, parameter); } command.Parameters.Add(dbParam); } } if (dbConnection.State != ConnectionState.Open) { await dbConnection.OpenAsync().ConfigureAwait(false); } var response = new OperationResponse { ReturnType = returnType }; try { switch (returnType) { case OperationReturnType.NonQuery: response.RecordsAffected = await command.ExecuteNonQueryAsync().ConfigureAwait(false); break; case OperationReturnType.MultiResult: case OperationReturnType.SingleResult: case OperationReturnType.SingleRow: var behavior = CommandBehavior.Default; switch (returnType) { case OperationReturnType.SingleResult: behavior = CommandBehavior.SingleResult; break; case OperationReturnType.SingleRow: behavior = CommandBehavior.SingleRow; break; default: closeConnection = false; break; } if (closeConnection) { behavior |= CommandBehavior.CloseConnection; } closeConnection = false; response.Value = await command.ExecuteReaderAsync(behavior).ConfigureAwait(false); break; case OperationReturnType.Scalar: response.Value = await command.ExecuteScalarAsync().ConfigureAwait(false); break; } // Handle output parameters if (outputParameters != null) { foreach (var entry in outputParameters) { entry.Value.Value = Convert.IsDBNull(entry.Key.Value) ? null : entry.Key.Value; } } } catch (Exception ex) { if (captureException) { response.Exception = ex; } else { throw; } } finally { command.Dispose(); if (dbConnection != null && (closeConnection || response.HasErrors)) { dbConnection.Close(); } } return(response); }
private static Tuple <string, Param[], List <object> > GetCommitStatement(ChangeNode rootNode, DbConnection connection) { var dialect = DialectFactory.GetProvider(connection); var dataEntities = new List <object>(); var sql = new StringBuilder(); var statementId = 0; // Inserts var newNodes = GetChanges(rootNode, ObjectState.New); var tableCreated = false; var tempTableName = dialect.GetTemporaryTableName("ID"); var allParameters = new List <Param>(); foreach (var newNode in newNodes.Where(n => n.IsObject)) { var item = newNode.Value; if (item != null) { dataEntities.Add(item); } else { continue; } var objectType = newNode.Value.GetType(); var propertyMap = Reflector.GetPropertyMap(objectType); var autoGenProperty = propertyMap.Where(p => p.Key.CanWrite && p.Value != null && p.Value.IsAutoGenerated).Select(p => p.Key).FirstOrDefault(); var autoGenType = DbType.String; if (!tableCreated) { if (autoGenProperty != null) { autoGenType = Reflector.ClrToDbType(autoGenProperty.PropertyType); } sql.AppendFormat(dialect.CreateTemporaryTable("ID", new Dictionary <string, DbType> { { "StatementId", DbType.Int32 }, { "GeneratedId", autoGenType }, { "ParameterName", DbType.AnsiString }, { "PropertyName", DbType.AnsiString } })).AppendLine(); tableCreated = true; } var parameters = ObjectExtensions.GetInsertParameters(newNode.Value, propertyMap, statementId); allParameters.AddRange(parameters); if (parameters.Length > 0) { string commandName = SqlBuilder.GetInsertStatement(objectType, parameters, dialect); var autoGenParameter = parameters.FirstOrDefault(p => p.IsAutoGenerated); if (autoGenParameter != null) { sql.AppendFormat(dialect.DeclareVariable(autoGenParameter.Name, autoGenType)).AppendLine(); sql.AppendFormat(dialect.AssignVariable(autoGenParameter.Name, autoGenParameter.Type.GetDefault())).AppendLine(); } sql.AppendLine(commandName); if (autoGenParameter != null) { sql.AppendFormat(dialect.ComputeAutoIncrement(autoGenParameter.Name, () => SqlBuilder.GetTableNameForSql(objectType, dialect))).AppendLine(); sql.AppendFormat("INSERT INTO " + tempTableName + " ({4}StatementId{5}, {4}GeneratedId{5}, {4}ParameterName{5}, {4}PropertyName{5}) VALUES ({0}, {1}, '{2}', '{3}')", statementId, dialect.EvaluateVariable(dialect.ParameterPrefix + autoGenParameter.Name), autoGenParameter.Name, autoGenProperty.Name, dialect.IdentifierEscapeStartCharacter, dialect.IdentifierEscapeEndCharacter).AppendLine(); } statementId++; } } if (newNodes.Count > 0) { sql.AppendLine("SELECT * FROM " + tempTableName); } if (tableCreated && !dialect.SupportsTemporaryTables) { sql.AppendLine("DROP TABLE " + tempTableName); } // Updates var dirtyNodes = GetChanges(rootNode, ObjectState.Dirty); var dirtyNodeParents = dirtyNodes.Where(n => n.IsSimpleLeaf).Select(n => n.Parent).Distinct(); foreach (var dirtyNode in dirtyNodeParents) { var objectType = dirtyNode.Value.GetType(); var propertyMap = Reflector.GetPropertyMap(objectType).ToDictionary(p => p.Key.Name, p => p); var parameters = new List <Param>(); foreach (var change in dirtyNode.Nodes.Where(n => n.IsSimpleLeaf)) { KeyValuePair <PropertyInfo, ReflectedProperty> map; if (propertyMap.TryGetValue(change.PropertyName, out map)) { var property = map.Key; var parameterName = change.PropertyName; if (map.Value != null && !string.IsNullOrEmpty(map.Value.ParameterName)) { parameterName = map.Value.ParameterName; } parameters.Add(new Param { Name = parameterName + "_" + statementId, Value = change.Value, Source = MapColumnAttribute.GetMappedColumnName(property) }); } } var primaryKey = new List <Param>(); foreach (var primaryKeyMap in propertyMap.Values.Where(p => p.Value.IsPrimaryKey)) { var value = dirtyNode.Value.Property(primaryKeyMap.Key.Name); var parameterName = primaryKeyMap.Key.Name; if (primaryKeyMap.Value != null && !string.IsNullOrEmpty(primaryKeyMap.Value.ParameterName)) { parameterName = primaryKeyMap.Value.ParameterName; } primaryKey.Add(new Param { Name = parameterName + "_" + statementId, Value = value, Source = MapColumnAttribute.GetMappedColumnName(primaryKeyMap.Key) }); } var commandName = SqlBuilder.GetUpdateStatement(objectType, parameters, primaryKey, dialect); allParameters.AddRange(parameters); allParameters.AddRange(primaryKey); sql.Append(commandName).AppendLine(); statementId++; } // Deletes var deletedNodes = GetChanges(rootNode, ObjectState.Deleted); foreach (var deletedNode in deletedNodes) { var objectType = deletedNode.Value.GetType(); var propertyMap = Reflector.GetPropertyMap(objectType); var parameters = ObjectExtensions.GetDeleteParameters(deletedNode.Value, propertyMap, statementId); var commandName = SqlBuilder.GetDeleteStatement(objectType, parameters, dialect); allParameters.AddRange(parameters); sql.Append(commandName).AppendLine(); statementId++; } return(Tuple.Create(sql.ToString(), allParameters.ToArray(), dataEntities)); }