CSharp:Automatismo caricamento Entità
From Aino Wiki
Contents
Helper di trasformazione: DataRow-->CustomObject
Esempio 1
public static T GetEntity<T>(DataRow dr) { bool columnCanNotCorrespond = true; return GetEntity<T>(dr, columnCanNotCorrespond); } /// <summary> /// Riempie una Entità con i valori presenti in un DataRow automaticamente. /// Se un valore è NULLO inserirà il valore di default. /// L'automatismo funzione solo se i nomi delle colonne (campi dal Db\DataRow) corrispondono ai nomi /// delle properties; se una Property non ha colonna del DataRow semplicemente è valorizzata al Default /// (come dopo una istanzizione dell'oggetto mediante "new"). Se una colonna esiste ma non c'è la /// corrispondente proprietà la segnalazione dell'eccezione dipenderà dal flag: columnCanNotCorrespond /// </summary> /// <typeparam name="T"></typeparam> /// <param name="dr"></param> /// <param name="columnCanNotCorrespond">Se true, non scatta eccezione se c'è una colonna che non /// è corrispondente ad una Property</param> /// <returns></returns> public static T GetEntity<T>(DataRow dr, bool columnCanNotCorrespond) { Type entityType = typeof(T); T entity = (T)entityType.Assembly.CreateInstance(entityType.FullName); string columnName = string.Empty; string strErrorMsg = string.Empty; try { if (columnCanNotCorrespond) { foreach (DataColumn dc in dr.Table.Columns) { columnName = dc.ColumnName; object columnValue = dr[columnName]; //La Property Esiste? if (entity.GetType().GetProperty(columnName , BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase) != null) { //Assegnazione condizionata affinchè rimanga il valore di Default nel caso il valore da inserire sia nullo if (columnValue != DBNull.Value) { PropertyInfo prop = entity.GetType().GetProperty(columnName , BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase); if (prop.PropertyType.ToString() == "System.Boolean") { prop.SetValue(entity, bool.Parse(columnValue.ToString()), null); } else if (prop.PropertyType.ToString() == "System.DateTime") { prop.SetValue(entity, DateTime.Parse(columnValue.ToString()), null); } else if (prop.PropertyType.ToString() == "System.Int32") { prop.SetValue(entity, Int32.Parse(columnValue.ToString()), null); } //CUSTOM types, enum? else if (prop.PropertyType.ToString().Contains("Enum")) { //ToDo } else //Standard Type { prop.SetValue(entity, columnValue, null); } } } } } else //Scatterà eccezione se la Property non corrisponde alla colonna! { foreach (DataColumn dc in dr.Table.Columns) { columnName = dc.ColumnName; object columnValue = dr[columnName]; //Assegnazione condizionata affinchè rimanga il valore di Default nel caso il valore da inserire sia nullo if (columnValue != DBNull.Value) { entity.GetType().GetProperty(columnName , BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase).SetValue(entity, columnValue, null); } } } } catch (Exception ex) { strErrorMsg = string.Format("Method GetEntity<T>, column '{0}'\r\n{1}", columnName, ex.Message); throw new Exception(strErrorMsg); } return (T)entity; }
Esempio 2
private static Dictionary<string, PropertyInfo[]> _entitiesFields = new Dictionary<string, PropertyInfo[]>(); /// <summary> /// Data una DataRow, restituisce un'entità /// </summary> /// <param name="dr"></param> /// <param name="Entity"></param> /// <returns></returns> private static T FromDataRowToEntity<T>(DataRow dr) where T : new() { T result = new T(); if (result != null && dr != null) { string fullyName = typeof(T).FullName; lock (_entitiesFields) { if (!_entitiesFields.ContainsKey(fullyName)) { // Ottengo tutti i campi della entity _entitiesFields.Add(fullyName, result.GetType().GetProperties()); } } PropertyInfo[] properties = _entitiesFields[fullyName]; if (properties != null) { for (int i = 0; i < properties.Length; i++) { #region per ogni campo dell'entità, cerco il valore nella riga e glielo assegno PropertyInfo property = properties[i]; string propertyName = property.Name; if (dr.Table.Columns.Contains(propertyName)) property.SetValue(result, GetFieldValue(property, dr[propertyName]), null); #endregion } } } return result; } /// <summary> /// Data una DataTable, restituisce una collezione di entità /// </summary> /// <param name="dt"></param> /// <returns></returns> private static List<T> FromDataTableToListOfEntity<T>(DataTable dt) where T : new() { List<T> tmp_list = new List<T>(); if (dt != null) { foreach (DataRow dr in dt.Rows) { T toAdd = FromDataRowToEntity<T>(dr); if (toAdd != null) tmp_list.Add(toAdd); } } return tmp_list; }
Trasformazione Lista di Entità in DataTable
/// <summary> /// Converts a Generic List into a DataTable. /// </summary> /// <param name="genericList">Generic list</param> /// <returns>DataTable object</returns> public static DataTable GenericListToDataTable(object genericList) { DataTable dataTable = null; Type listType = genericList.GetType(); if (listType.IsGenericType & (genericList != null)) { //determine the underlying type the List<> contains Type elementType = listType.GetGenericArguments()[0]; //create empty table -- give it a name in case //it needs to be serialized dataTable = new DataTable(elementType.Name + "List"); //define the table -- add a column for each public //property or field MemberInfo[] memberInfos = elementType.GetMembers(BindingFlags.Public | BindingFlags.Instance); foreach (MemberInfo memberInfo in memberInfos) { if (memberInfo.MemberType == MemberTypes.Property) { PropertyInfo propertyInfo = memberInfo as PropertyInfo; if (IsNullableType(propertyInfo.PropertyType)) { dataTable.Columns.Add(propertyInfo.Name, new NullableConverter(propertyInfo.PropertyType).UnderlyingType); } else { dataTable.Columns.Add(propertyInfo.Name, propertyInfo.PropertyType); } } else if (memberInfo.MemberType == MemberTypes.Field) { FieldInfo fieldInfo = memberInfo as FieldInfo; dataTable.Columns.Add(fieldInfo.Name, fieldInfo.FieldType); } } //populate the table IList listData = genericList as IList; foreach (object record in listData) { int index = 0; object[] fieldValues = new object[dataTable.Columns.Count]; foreach (DataColumn columnData in dataTable.Columns) { MemberInfo memberInfo = elementType.GetMember(columnData.ColumnName)[0]; if (memberInfo.MemberType == MemberTypes.Property) { PropertyInfo propertyInfo = memberInfo as PropertyInfo; fieldValues[index] = propertyInfo.GetValue(record, null); } else if (memberInfo.MemberType == MemberTypes.Field) { FieldInfo fieldInfo = memberInfo as FieldInfo; fieldValues[index] = fieldInfo.GetValue(record); } index += 1; } dataTable.Rows.Add(fieldValues); } } return dataTable; } /// <summary> /// Check if a type is Nullable type /// </summary> /// <param name="propertyType">Type to be checked</param> /// <returns>true/false</returns> /// <remarks></remarks> private static bool IsNullableType(Type propertyType) { return (propertyType.IsGenericType) && (object.ReferenceEquals(propertyType.GetGenericTypeDefinition(), typeof(Nullable<>))); }
Helper mapping e copia: CustomObject1-->CustomObject2
Versione semplificata:
private static T MapCustom<T>(object entitySource) { Type entityDestType = typeof(T); Type entitySourceType = entitySource.GetType(); T entityDestination = (T)entityDestType.Assembly.CreateInstance(entityDestType.FullName); foreach (PropertyInfo piSrc in entitySourceType.GetProperties(BindingFlags.FlattenHierarchy // Mamber static and public, nested type are not returned )) { if (piSrc.CanRead) { foreach (PropertyInfo piDst in entityDestType.GetProperties(BindingFlags.FlattenHierarchy // Nested type are not returned )) { if (piSrc.Name.Equals(piDst.Name, StringComparison.InvariantCultureIgnoreCase)) { if (piSrc.PropertyType == piDst.PropertyType) { if (piDst.CanWrite) { // value object srcVal = piSrc.GetValue(entitySource, null); piDst.SetValue(entityDestination, srcVal, null); } } else { // Managing nullable values .... } } } } } return (T)entityDestination; }
Versione compatta e realistica:
private T MapCustom<T>(object entitySource) { Type entityDestType = typeof(T); Type entitySourceType = entitySource.GetType(); T entityDestination = (T)entityDestType.Assembly.CreateInstance(entityDestType.FullName); string srcPropertyName = string.Empty; string csvNotMatchingPropertiesName = string.Empty; // Not used BUT may be logged for debug purpose! try { // Arrray of member static and public, nested type are not returned: PropertyInfo[] arrPropertyInfoDest = entityDestType.GetProperties() //BindingFlags.FlattenHierarchy .Where(pd => pd.CanWrite).ToArray(); // For each member static and public, nested type are not returned: foreach (PropertyInfo piSrc in entitySourceType.GetProperties() //BindingFlags.FlattenHierarchy .Where(ps => ps.CanRead)) { srcPropertyName = piSrc.Name; PropertyInfo piDst = arrPropertyInfoDest.SingleOrDefault(i => i.Name.Equals(piSrc.Name, StringComparison.InvariantCultureIgnoreCase) && i.PropertyType == piSrc.PropertyType); if (piDst != null) { // Set value: object srcVal = piSrc.GetValue(entitySource, null); piDst.SetValue(entityDestination, srcVal, null); } else { csvNotMatchingPropertiesName += string.Format("{0},", srcPropertyName); } } } catch (Exception ex) { priceListManager.Error(string.Format("Error on source property '{0}'.\r\n{1}", srcPropertyName, ex.Message), ex); // ToDo Manage exception! } return (T)entityDestination; }