using System; using System.Data.Common; using System.Data; using System.Collections.Generic; using System.Linq; using System.Reflection; namespace Developpez.Dotnet.Data { /// /// Fournit des méthodes d'extension pour faciliter l'utilisation des classes ADO.NET /// public static class DataExtensions { #region Méthodes d'extension pour DbConnection /// /// Crée une commande à partir d'une connection et d'une requête /// /// La connection /// Le texte de la requête /// Une commande pour la connexion et la requête spécifiées public static DbCommand CreateCommand(this DbConnection connection, string commandText) { DbCommand command = connection.CreateCommand(); command.CommandText = commandText; return command; } #endregion #region Méthodes d'extension pour DbCommand /// /// Ajoute à la commande un paramètre avec les options spécifiées /// /// La commande à laquelle ajouter un paramètre /// Le nom du paramètre /// Le type du paramètre /// Le paramètre créé public static DbParameter AddParameter(this DbCommand command, string name, DbType dbType) { return AddParameter(command, name, dbType, 0, ParameterDirection.Input); } /// /// Ajoute à la commande un paramètre avec les options spécifiées /// /// La commande à laquelle ajouter un paramètre /// Le nom du paramètre /// Le type du paramètre /// La taille du paramètre /// Le paramètre créé public static DbParameter AddParameter(this DbCommand command, string name, DbType dbType, int size) { return AddParameter(command, name, dbType, size, ParameterDirection.Input); } /// /// Ajoute à la commande un paramètre avec les options spécifiées /// /// La commande à laquelle ajouter un paramètre /// Le nom du paramètre /// Le type du paramètre /// La direction du paramètre /// Le paramètre créé public static DbParameter AddParameter(this DbCommand command, string name, DbType dbType, ParameterDirection direction) { DbParameter parameter = command.CreateParameter(); parameter.ParameterName = name; parameter.DbType = dbType; parameter.Direction = direction; command.Parameters.Add(parameter); return parameter; } /// /// Ajoute à la commande un paramètre avec les options spécifiées /// /// La commande à laquelle ajouter un paramètre /// Le nom du paramètre /// Le type du paramètre /// La taille du paramètre /// La direction du paramètre /// Le paramètre créé public static DbParameter AddParameter(this DbCommand command, string name, DbType dbType, int size, ParameterDirection direction) { DbParameter parameter = command.CreateParameter(); parameter.ParameterName = name; parameter.DbType = dbType; parameter.Direction = direction; parameter.Size = size; command.Parameters.Add(parameter); return parameter; } #endregion #region Méthodes d'extension pour IDataRecord /// /// Récupère la valeur de le colonne spécifiée en tant que Boolean /// /// Le IDataRecord qui contient les données /// Le nom de la colonne à récupérer /// La valeur de la colonne public static bool GetBoolean(this IDataRecord record, string name) { int i = record.GetOrdinal(name); return record.GetBoolean(i); } /// /// Récupère la valeur de le colonne spécifiée en tant que Byte /// /// Le IDataRecord qui contient les données /// Le nom de la colonne à récupérer /// La valeur de la colonne public static byte GetByte(this IDataRecord record, string name) { int i = record.GetOrdinal(name); return record.GetByte(i); } /// /// Récupère la valeur de le colonne spécifiée en tant que Char /// /// Le IDataRecord qui contient les données /// Le nom de la colonne à récupérer /// La valeur de la colonne public static char GetChar(this IDataRecord record, string name) { int i = record.GetOrdinal(name); return record.GetChar(i); } /// /// Récupère la valeur de le colonne spécifiée en tant que DateTime /// /// Le IDataRecord qui contient les données /// Le nom de la colonne à récupérer /// La valeur de la colonne public static DateTime GetDateTime(this IDataRecord record, string name) { int i = record.GetOrdinal(name); return record.GetDateTime(i); } /// /// Récupère la valeur de le colonne spécifiée en tant que Decimal /// /// Le IDataRecord qui contient les données /// Le nom de la colonne à récupérer /// La valeur de la colonne public static decimal GetDecimal(this IDataRecord record, string name) { int i = record.GetOrdinal(name); return record.GetDecimal(i); } /// /// Récupère la valeur de le colonne spécifiée en tant que Double /// /// Le IDataRecord qui contient les données /// Le nom de la colonne à récupérer /// La valeur de la colonne public static double GetDouble(this IDataRecord record, string name) { int i = record.GetOrdinal(name); return record.GetDouble(i); } /// /// Récupère la valeur de le colonne spécifiée en tant que Float /// /// Le IDataRecord qui contient les données /// Le nom de la colonne à récupérer /// La valeur de la colonne public static float GetFloat(this IDataRecord record, string name) { int i = record.GetOrdinal(name); return record.GetFloat(i); } /// /// Récupère la valeur de le colonne spécifiée en tant que Guid /// /// Le IDataRecord qui contient les données /// Le nom de la colonne à récupérer /// La valeur de la colonne public static Guid GetGuid(this IDataRecord record, string name) { int i = record.GetOrdinal(name); return record.GetGuid(i); } /// /// Récupère la valeur de le colonne spécifiée en tant que Int16 /// /// Le IDataRecord qui contient les données /// Le nom de la colonne à récupérer /// La valeur de la colonne public static short GetInt16(this IDataRecord record, string name) { int i = record.GetOrdinal(name); return record.GetInt16(i); } /// /// Récupère la valeur de le colonne spécifiée en tant que Int32 /// /// Le IDataRecord qui contient les données /// Le nom de la colonne à récupérer /// La valeur de la colonne public static int GetInt32(this IDataRecord record, string name) { int i = record.GetOrdinal(name); return record.GetInt32(i); } /// /// Récupère la valeur de le colonne spécifiée en tant que Int64 /// /// Le IDataRecord qui contient les données /// Le nom de la colonne à récupérer /// La valeur de la colonne public static long GetInt64(this IDataRecord record, string name) { int i = record.GetOrdinal(name); return record.GetInt64(i); } /// /// Récupère la valeur de le colonne spécifiée en tant que String /// /// Le IDataRecord qui contient les données /// Le nom de la colonne à récupérer /// La valeur de la colonne public static string GetString(this IDataRecord record, string name) { int i = record.GetOrdinal(name); return record.GetString(i); } /// /// Récupère la valeur de le colonne spécifiée /// /// Le IDataRecord qui contient les données /// Le nom de la colonne à récupérer /// La valeur de la colonne public static object GetValue(this IDataRecord record, string name) { int i = record.GetOrdinal(name); return record.GetValue(i); } /// /// Lit un flux binaire de la colonne spécifiée /// /// Le IDataRecord qui contient les données /// Le nom de la colonne à lire /// La position à laquelle commence la lecture dans la colonne /// Le buffer de destination /// La position à laquelle commence l'écriture dans le buffer /// Le nombre maximum d'octets à lire /// Le nombre d'octets lus public static long GetBytes(this IDataRecord record, string name, long dataOffset, byte[] buffer, int bufferOffset, int length) { int i = record.GetOrdinal(name); return record.GetBytes(i, dataOffset, buffer, bufferOffset, length); } /// /// Lit un flux de caractères de la colonne spécifiée /// /// Le IDataRecord qui contient les données /// Le nom de la colonne à lire /// La position à laquelle commence la lecture dans la colonne /// Le buffer de destination /// La position à laquelle commence l'écriture dans le buffer /// Le nombre maximum de caractères à lire /// Le nombre de caractères lus public static long GetChars(this IDataRecord record, string name, long dataOffset, char[] buffer, int bufferOffset, int length) { int i = record.GetOrdinal(name); return record.GetChars(i, dataOffset, buffer, bufferOffset, length); } /// /// Indique si la colonne spécifiée a la valeur DBNull /// /// Le IDataRecord qui contient les données /// Le nom de la colonne à lire /// True si la colonne vaut DBNull, false sinon public static bool IsDBNull(this IDataRecord record, string name) { int i = record.GetOrdinal(name); return record.IsDBNull(i); } /// /// Renvoie le nom du type de données de la colonne spécifiée /// /// Le IDataRecord qui contient les données /// Le nom de la colonne dont on veut obtenir le type de données /// Le nom du type de données de la colonne public static string GetDataTypeName(this IDataRecord record, string name) { int i = record.GetOrdinal(name); return record.GetDataTypeName(i); } /// /// Renvoie le type .NET de la colonne spécifiée /// /// Le IDataRecord qui contient les données /// Le nom de la colonne dont on veut obtenir le type .NET /// Le nom type .NET de la colonne public static Type GetFieldType(this IDataRecord record, string name) { int i = record.GetOrdinal(name); return record.GetFieldType(i); } /// /// Renvoie la valeur de la colonne spécifiée en tant que valeur du type spécifié /// /// Le type de retour souhaité /// Le IDataRecord qui contient les données /// L'index de la colonne à récupérer /// true pour tenter de convertir la valeur si elle n'est pas de type T ; false pour effectuer un cast direct /// La valeur de la colonne /// La conversion spécifiée n'est pas valide public static T Field(this IDataRecord record, int ordinal, bool tryConvert) { if (tryConvert) return ConvertT.Convert(record[ordinal]); else return UnboxT.Unbox(record[ordinal]); } /// /// Renvoie la valeur de la colonne spécifiée en tant que valeur du type spécifié /// /// Le type de retour souhaité /// Le IDataRecord qui contient les données /// L'index de la colonne à récupérer /// La valeur de la colonne /// La conversion spécifiée n'est pas valide public static T Field(this IDataRecord record, int ordinal) { return record.Field(ordinal, false); } /// /// Renvoie la valeur de la colonne spécifiée en tant que valeur du type spécifié /// /// Le type de retour souhaité /// Le IDataRecord qui contient les données /// Le nom de la colonne à récupérer /// true pour tenter de convertir la valeur si elle n'est pas de type T ; false pour effectuer un cast direct /// La valeur de la colonne /// La conversion spécifiée n'est pas valide public static T Field(this IDataRecord record, string name, bool tryConvert) { int i = record.GetOrdinal(name); return record.Field(i, tryConvert); } /// /// Renvoie la valeur de la colonne spécifiée en tant que valeur du type spécifié /// /// Le type de retour souhaité /// Le IDataRecord qui contient les données /// Le nom de la colonne à récupérer /// La valeur de la colonne /// La conversion spécifiée n'est pas valide public static T Field(this IDataRecord record, string name) { int i = record.GetOrdinal(name); return record.Field(i, false); } #region Classes utilitaires UnboxT pour convertir les valeurs de champ // Tiré de la classe System.Data.DataRowExtensions de .NET 3.5 private static class UnboxT { internal static readonly Converter Unbox; static UnboxT() { Unbox = Create(typeof(T)); } private static Converter Create(Type type) { if (!type.IsValueType) { return new Converter(ReferenceField); } if ((type.IsGenericType && !type.IsGenericTypeDefinition) && (typeof(Nullable<>) == type.GetGenericTypeDefinition())) { return (Converter)Delegate.CreateDelegate(typeof(Converter), typeof(UnboxT).GetMethod("NullableField", BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(new Type[] { type.GetGenericArguments()[0] })); } return new Converter(ValueField); } private static TElem? NullableField(object value) where TElem : struct { if (DBNull.Value == value) { return null; } return new TElem?((TElem)value); } private static T ReferenceField(object value) { if (DBNull.Value != value) { return (T)value; } return default(T); } private static T ValueField(object value) { if (DBNull.Value == value) { throw new InvalidCastException(string.Format(ExceptionMessages.InvalidCastFromTo, typeof(DBNull), typeof(T))); } return (T)value; } } private static class ConvertT { internal static readonly Converter Convert; static ConvertT() { Convert = Create(typeof(T)); } private static Converter Create(Type type) { if (!type.IsValueType) { return new Converter(ReferenceField); } if ((type.IsGenericType && !type.IsGenericTypeDefinition) && (typeof(Nullable<>) == type.GetGenericTypeDefinition())) { return (Converter)Delegate.CreateDelegate(typeof(Converter), typeof(ConvertT).GetMethod("NullableField", BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(new Type[] { type.GetGenericArguments()[0] })); } return new Converter(ValueField); } private static TElem? NullableField(object value) where TElem : struct { if (null == value || DBNull.Value == value) { return null; } TElem nonNullValue = (TElem)System.Convert.ChangeType(value, typeof(TElem)); return new TElem?(nonNullValue); } private static T ReferenceField(object value) { if (null != value && DBNull.Value != value) { return (T)System.Convert.ChangeType(value, typeof(T)); } return default(T); } private static T ValueField(object value) { if (DBNull.Value == value) { throw new InvalidCastException(string.Format(ExceptionMessages.InvalidCastFromTo, typeof(DBNull), typeof(T))); } if (null == value) { throw new InvalidCastException(ExceptionMessages.InvalidCastFromNullToValueType); } return (T)System.Convert.ChangeType(value, typeof(T)); } } #endregion #endregion #region Méthodes d'extension pour DbDataReader /// /// Renvoie un DbDataReader comme une séquence de IDataRecord /// /// Le DbDataReader à énumérer /// Une séquence de IDataRecord public static IEnumerable AsEnumerable(this DbDataReader reader) { return reader.Cast(); } #endregion #region Méthodes d'extension pour DbDataAdapter /// /// Ajoute un handler d'évènement RowUpdating à un DbDataAdapter /// /// L'adapteur pour lequel ajouter un handler d'évènement /// Le handler d'évènement à ajouter public static void AddRowUpdatingHandler(this DbDataAdapter adapter, EventHandler handler) { adapter.CheckArgumentNull("adapter"); handler.CheckArgumentNull("handler"); AddEventHandler(adapter, "RowUpdating", handler); } /// /// Ajoute un handler d'évènement RowUpdated à un DbDataAdapter /// /// L'adapteur pour lequel ajouter un handler d'évènement /// Le handler d'évènement à ajouter public static void AddRowUpdatedHandler(this DbDataAdapter adapter, EventHandler handler) { adapter.CheckArgumentNull("adapter"); handler.CheckArgumentNull("handler"); AddEventHandler(adapter, "RowUpdated", handler); } /// /// Enlève un handler d'évènement RowUpdating d'un DbDataAdapter /// /// L'adapteur pour lequel enlever un handler d'évènement /// Le handler d'évènement à enlever public static void RemoveRowUpdatingHandler(this DbDataAdapter adapter, EventHandler handler) { adapter.CheckArgumentNull("adapter"); handler.CheckArgumentNull("handler"); RemoveEventHandler(adapter, "RowUpdating", handler); } /// /// Enlève un handler d'évènement RowUpdated d'un DbDataAdapter /// /// L'adapteur pour lequel enlever un handler d'évènement /// Le handler d'évènement à enlever public static void RemoveRowUpdatedHandler(this DbDataAdapter adapter, EventHandler handler) { adapter.CheckArgumentNull("adapter"); handler.CheckArgumentNull("handler"); RemoveEventHandler(adapter, "RowUpdated", handler); } private static void AddEventHandler(object target, string eventName, Delegate handler) { Type targetType = target.GetType(); EventInfo evt = targetType.GetEvent(eventName); if (evt == null) { throw new InvalidOperationException(string.Format(ExceptionMessages.TypeDoesntImplementEvent, targetType, eventName)); } evt.AddEventHandler(target, ChangeType(evt.EventHandlerType, handler)); } private static void RemoveEventHandler(object target, string eventName, Delegate handler) { Type targetType = target.GetType(); EventInfo evt = targetType.GetEvent(eventName); if (evt == null) { throw new InvalidOperationException(string.Format(ExceptionMessages.TypeDoesntImplementEvent, targetType, eventName)); } evt.RemoveEventHandler(target, ChangeType(evt.EventHandlerType, handler)); } private static Delegate ChangeType(Type targetType, Delegate d) { return Delegate.CreateDelegate(targetType, d.Target, d.Method); } #endregion } }