/* * * (c) Copyright Ascensio System Limited 2010-2018 * * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). * In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that * Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights. * * THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR * FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html * * You can contact Ascensio System SIA by email at sales@onlyoffice.com * * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. * * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains * relevant author attributions when distributing the software. If the display of the logo in its graphic * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" * in every copy of the program you distribute. * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. * */ using System; using System.Collections.Generic; using System.Data; using System.Data.Common; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using ASC.Common.Data.Sql; namespace ASC.Common.Data { public static class DataExtensions { public static List ExecuteList(this DbConnection connection, string sql, params object[] parameters) { using var command = connection.CreateCommand(); return command.ExecuteList(sql, parameters); } public static T ExecuteScalar(this DbConnection connection, string sql, params object[] parameters) { using var command = connection.CreateCommand(); return command.ExecuteScalar(sql, parameters); } public static int ExecuteNonQuery(this DbConnection connection, string sql, params object[] parameters) { using var command = connection.CreateCommand(); return command.ExecuteNonQuery(sql, parameters); } public static DbCommand CreateCommand(this DbConnection connection, string sql, params object[] parameters) { var command = connection.CreateCommand(); command.CommandText = sql; command.AddParameters(parameters); return command; } public static DbCommand AddParameter(this DbCommand command, string name, object value) { var p = command.CreateParameter(); if (!string.IsNullOrEmpty(name)) { p.ParameterName = name.StartsWith("@") ? name : "@" + name; } p.Value = GetParameterValue(value); command.Parameters.Add(p); return command; } public static object GetParameterValue(object value) { if (value == null) { return DBNull.Value; } if (value is Enum @enum) { return @enum.ToString("d"); } if (value is DateTime d) { return new DateTime(d.Year, d.Month, d.Day, d.Hour, d.Minute, d.Second, DateTimeKind.Unspecified); } return value; } public static DbCommand AddParameters(this DbCommand command, params object[] parameters) { if (parameters == null) return command; foreach (var value in parameters) { if (value != null && IsAnonymousType(value.GetType())) { foreach (var p in value.GetType().GetProperties()) { command.AddParameter(p.Name, p.GetValue(value, null)); } } else { command.AddParameter(null, value); } } return command; } public static List ExecuteList(this DbCommand command) { return ExecuteList(command, command.CommandText, null); } public static Task> ExecuteListAsync(this DbCommand command) { return ExecuteListAsync(command, command.CommandText, null); } public static List ExecuteList(this DbCommand command, string sql, params object[] parameters) { return ExecuteListReader(command.PrepareCommand(sql, parameters)); } public static Task> ExecuteListAsync(this DbCommand command, string sql, params object[] parameters) { return ExecuteListReaderAsync(command.PrepareCommand(sql, parameters)); } private static List ExecuteListReader(DbCommand command) { using var reader = command.ExecuteReader(); return ExecuteListReaderResult(reader); } private static async Task> ExecuteListReaderAsync(DbCommand command) { using var reader = await command.ExecuteReaderAsync(); return ExecuteListReaderResult(reader); } private static List ExecuteListReaderResult(IDataReader reader) { var result = new List(); var fieldCount = reader.FieldCount; while (reader.Read()) { result.Add(GetData(reader, fieldCount)); } return result; } public static T ExecuteScalar(this DbCommand command) { return ExecuteScalar(command, command.CommandText, null); } public static T ExecuteScalar(this DbCommand command, string sql, params object[] parameters) { command.PrepareCommand(sql, parameters); var scalar = command.ExecuteScalar(); if (scalar == null || scalar == DBNull.Value) { return default; } var scalarType = typeof(T); if (scalarType == typeof(object)) { return (T)scalar; } if (scalarType.Name == "Nullable`1") { scalarType = scalarType.GetGenericArguments()[0]; } return (T)Convert.ChangeType(scalar, scalarType); } public static async Task ExecuteScalarAsync(this DbCommand command, string sql, params object[] parameters) { command.PrepareCommand(sql, parameters); var scalar = await command.ExecuteScalarAsync(); if (scalar == null || scalar == DBNull.Value) { return default; } var scalarType = typeof(T); if (scalarType == typeof(object)) { return (T)scalar; } if (scalarType.Name == "Nullable`1") { scalarType = scalarType.GetGenericArguments()[0]; } return (T)Convert.ChangeType(scalar, scalarType); } public static int ExecuteNonQuery(this DbCommand command, string sql, params object[] parameters) { command.PrepareCommand(sql, parameters); return command.ExecuteNonQuery(); } public static Task ExecuteNonQueryAsync(this DbCommand command, string sql, params object[] parameters) { command.PrepareCommand(sql, parameters); return command.ExecuteNonQueryAsync(); } public static List ExecuteList(this DbCommand command, ISqlInstruction sql, ISqlDialect dialect) { ApplySqlInstruction(command, sql, dialect); return command.ExecuteList(); } public static Task> ExecuteListAsync(this DbCommand command, ISqlInstruction sql, ISqlDialect dialect) { ApplySqlInstruction(command, sql, dialect); return command.ExecuteListAsync(); } public static List ExecuteList(this DbCommand command, ISqlInstruction sql, ISqlDialect dialect, Converter mapper) { ApplySqlInstruction(command, sql, dialect); var result = new List(); using (var reader = command.ExecuteReader()) { while (reader.Read()) { result.Add(mapper(reader)); } } return result; } public static List ExecuteList(this DbCommand command, ISqlInstruction sql, ISqlDialect dialect, Converter mapper) { ApplySqlInstruction(command, sql, dialect); var result = new List(); using (var reader = command.ExecuteReader()) { var fieldCount = reader.FieldCount; while (reader.Read()) { result.Add(mapper(GetData(reader, fieldCount))); } } return result; } public static T ExecuteScalar(this DbCommand command, ISqlInstruction sql, ISqlDialect dialect) { ApplySqlInstruction(command, sql, dialect); return command.ExecuteScalar(); } public static int ExecuteNonQuery(this DbCommand command, ISqlInstruction sql, ISqlDialect dialect) { ApplySqlInstruction(command, sql, dialect); return command.ExecuteNonQuery(); } private static void ApplySqlInstruction(DbCommand command, ISqlInstruction sql, ISqlDialect dialect) { var sqlStr = sql.ToString(dialect); var parameters = sql.GetParameters(); command.Parameters.Clear(); var sqlParts = sqlStr.Split('?'); var sqlBuilder = new StringBuilder(); for (var i = 0; i < sqlParts.Length - 1; i++) { var name = "p" + i; command.AddParameter(name, parameters[i]); sqlBuilder.AppendFormat("{0}@{1}", sqlParts[i], name); } sqlBuilder.Append(sqlParts[^1]); command.CommandText = sqlBuilder.ToString(); } public static T Get(this IDataRecord r, int i) { if (r.IsDBNull(i)) { return default; } var value = r.GetValue(i); if (typeof(T) == typeof(Guid)) { value = r.GetGuid(i); } return (T)Convert.ChangeType(value, typeof(T)); } public static T Get(this IDataRecord r, string name) { return Get(r, r.GetOrdinal(name)); } private static bool IsAnonymousType(Type type) { return type.IsGenericType && (type.Attributes & TypeAttributes.NotPublic) == TypeAttributes.NotPublic && (type.Name.StartsWith("<>", StringComparison.OrdinalIgnoreCase) || type.Name.StartsWith("VB$", StringComparison.OrdinalIgnoreCase)) && (type.Name.Contains("AnonymousType") || type.Name.Contains("AnonType")) && Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute), false); } private static DbCommand PrepareCommand(this DbCommand command, string sql, params object[] parameters) { command.CommandText = sql; if (parameters != null) { command.Parameters.Clear(); command.AddParameters(parameters); } return command; } private static object[] GetData(IDataRecord reader, int fieldCount) { var row = new object[fieldCount]; for (var i = 0; i < fieldCount; i++) { row[i] = reader[i]; if (DBNull.Value.Equals(row[i])) row[i] = null; } return row; } } }