private static void GetEntityValues <TEntity>(DataRow dataRow, ConvertToPrimitive convertToPrimitive, TEntity obj) { var properties = typeof(TEntity).GetProperties() .Where(p => !p.GetCustomAttributes(typeof(NotMapped), true).Any() && !p.GetCustomAttributes(typeof(OneToManyRelation), true).Any() && !p.GetCustomAttributes(typeof(OneToOneRelation), true).Any() ); var colunmsNames = dataRow.Table.Columns; if (properties != null && properties.Any()) { ConvertToPrimitive convert = convertToPrimitive != null ? convertToPrimitive : new ConvertToPrimitive(); foreach (var prop in properties) { var attr = prop.GetCustomAttributes(typeof(ColumnName), true); string name = attr.Any() ? (attr.Single() as ColumnName).Name : prop.Name; if (dataRow.Table.Columns.Contains(name) && dataRow[name] != DBNull.Value) { var value = dataRow[name]; convert.Convert <TEntity>(prop, obj, value); } } } }
private static TEntity GetEntity <TEntity>(DataRow dataRow, DataTable[] dataTables, ConvertToPrimitive convertToPrimitive, object parentObj, bool oneToOneRelationRequired) { if (dataRow == null) { throw new ArgumentNullException(); } TEntity obj = Activator.CreateInstance <TEntity>(); //get entity values for all properties mapped that they don't have an one to one or one to many attribute. GetEntityValues(dataRow, convertToPrimitive, obj); if (dataTables != null && dataTables.Any()) { //get all the one to one relational entities. GetOneToOneEntity(dataTables, convertToPrimitive, obj, oneToOneRelationRequired); //get all the one to many relational entities. GetOneToManyEntities(dataTables, convertToPrimitive, obj); } //set the navegation property if (parentObj != null) { var propertyInfo = typeof(TEntity).GetProperties() .Where(p => p.PropertyType == parentObj.GetType() && p.GetCustomAttributes(typeof(ParentNavigation), true).Any()).SingleOrDefault(); if (propertyInfo != null) { propertyInfo.SetValue(obj, parentObj, null); } } return((TEntity)obj); }
/// <summary> /// Extension method of datatable that return a list of entity objects. /// </summary> /// <typeparam name="TEntity">Type of the new entity.</typeparam> /// <param name="dataTable">Datatable that contain the data to be converted.</param> /// <param name="filter">Function that allows to filter data before be converted to the entities. It apply to the rows in the main datatable.</param> /// <param name="dataTables">Array of Datatables that contain the data to be converted for the relation entities.</param> /// <param name="convertToPrimitive">Expecific class that define convertion to the diferents primitive types.</param> /// <param name="oneToOneRelationRequired">Boolean that indicated when the one to one relation are required.</param> /// <returns>An IList of the new entity.</returns> public static IList <TEntity> MapToEntity <TEntity>(this DataTable dataTable, Func <DataTable, DataRow[]> filter, DataTable[] dataTables = null, ConvertToPrimitive convertToPrimitive = null, bool oneToOneRelationRequired = false) where TEntity : class { if (dataTable == null) { throw new ArgumentNullException("Datatable is Null"); } var datarows = dataTable.Select(); if (datarows == null) { throw new ArgumentNullException("Datarows is Null"); } if (filter != null) { datarows = filter(dataTable); } IList <TEntity> entities = new List <TEntity>(); try { for (int i = 0; i < datarows.Length; i++) { entities.Add(GetEntity <TEntity>(datarows[i], dataTables, convertToPrimitive, null, oneToOneRelationRequired)); } return(entities); } catch (Exception ex) { throw new Exception("Error mapping entity", ex); } }
/// <summary> /// Extension method of datatable that return a list of entity objects. /// </summary> /// <typeparam name="TEntity">Type of the new entity.</typeparam> /// <param name="dataTable">Datatable that contain the data to be converted.</param> /// <param name="dataTables">Array of Datatables that contain the data to be converted for the relation entities.</param> /// <param name="convertToPrimitive">Expecific class that define convertion to the diferents primitive types.</param> /// <param name="oneToOneRelationRequired">Boolean that indicated when the one to one relation are required.</param> /// <returns>An IList of the new entity.</returns> public static IList <TEntity> MapToEntity <TEntity>(this DataTable dataTable, DataTable[] dataTables, ConvertToPrimitive convertToPrimitive = null, bool oneToOneRelationRequired = false) where TEntity : class { return(MapToEntity <TEntity>(dataTable, null, dataTables, oneToOneRelationRequired: oneToOneRelationRequired)); }
private static void GetOneToManyEntities <TEntity>(DataTable[] dataTables, ConvertToPrimitive convertToPrimitive, TEntity parentObj) { var type = typeof(TEntity); var propertiesOneToMany = type.GetProperties().Where(p => !p.GetCustomAttributes(typeof(NotMapped), true).Any() && p.GetCustomAttributes(typeof(OneToManyRelation), true).Any()); /// var propertiesNames = type.GetProperties().Where(p => !p.GetCustomAttributes(typeof(NotMapped), true).Any() && p.GetCustomAttributes(typeof(ColumnName), true).Any()); var propertiesNamesObj = type.GetProperties().Where(p => !p.GetCustomAttributes(typeof(NotMapped), true).Any() && !p.GetCustomAttributes(typeof(OneToOneRelation), true).Any() && !p.GetCustomAttributes(typeof(OneToManyRelation), true).Any() && !p.GetCustomAttributes(typeof(ColumnName), true).Any()); if (propertiesOneToMany != null && propertiesOneToMany.Any()) { foreach (var prop in propertiesOneToMany) { var oneToManyAttrs = prop.GetCustomAttributes(typeof(OneToManyRelation), true); if (oneToManyAttrs.Count() > 1) { throw new System.InvalidOperationException(string.Format("Property {0} contains a duplicate attribute", prop.Name)); } OneToManyRelation attr = oneToManyAttrs.Single() as OneToManyRelation; var datatableOneToMany = dataTables.Where(dt => string.Compare(dt.TableName, attr.TableName, true) == 0).FirstOrDefault(); if (datatableOneToMany != null && datatableOneToMany.Rows.Count > 0) { PropertyInfo propertyParentKey = null; Dictionary <string, PropertyInfo> propertyParentKeys = new Dictionary <string, PropertyInfo>(); if (!string.IsNullOrWhiteSpace(attr.ParentKey)) { propertyParentKey = SearchPropertyParent(propertiesNames, propertiesNamesObj, attr.ParentKey); } else if (attr.ParentKeys != null && attr.ParentKeys.Any()) { foreach (var key in attr.ParentKeys) { var resul = SearchPropertyParent(propertiesNames, propertiesNamesObj, key); propertyParentKeys.Add(key, resul); } } else { throw new ArgumentException("One to Many relational attributes are required"); } Func <DataRow, bool> funcOneToMany = null; if (!string.IsNullOrWhiteSpace(attr.ChildrenKey) && !string.IsNullOrWhiteSpace(attr.ParentKey)) { if (propertyParentKey == null) { throw new ArgumentException(string.Format("One to Many relational attributes are required, ParentKey ({0}) property was not found", attr.ParentKey)); } funcOneToMany = (r) => { if (r.Table.Columns.Contains(attr.ChildrenKey)) { return(string.Equals(r[attr.ChildrenKey].ToString(), propertyParentKey.GetValue(parentObj, null).ToString(), StringComparison.OrdinalIgnoreCase)); } else { throw new ArgumentException(string.Format("One to Many relational attributes are required, ChildrenKey ({0}) column was not found", attr.ChildrenKey)); } }; } else if (attr.ChildrenKeys != null && attr.ChildrenKeys.Any() && propertyParentKeys != null && propertyParentKeys.Any() && !propertyParentKeys.Any(p => p.Value == null) && attr.ChildrenKeys.Count() == propertyParentKeys.Count()) { funcOneToMany = (r) => { bool resul = false; for (int i = 0; i < attr.ChildrenKeys.Length; i++) { if (propertyParentKeys.TryGetValue(attr.ParentKeys[i], out propertyParentKey)) { if (r.Table.Columns.Contains(attr.ChildrenKeys[i])) { resul = string.Equals(r[attr.ChildrenKeys[i]].ToString(), propertyParentKey.GetValue(parentObj, null).ToString(), StringComparison.OrdinalIgnoreCase); } else { throw new ArgumentException(string.Format("One to Many relational attributes are required, ChildrenKey ({0}) column was not found", attr.ChildrenKeys[i])); } } else { throw new ArgumentException("One to Many relational attributes must match"); } if (!resul) { break; } } return(resul); }; } else { throw new ArgumentException("One to Many relational attributes are required"); } var dataRows = datatableOneToMany.Select().Where(funcOneToMany).ToArray(); if (!dataRows.Any()) { continue; } MethodInfo method = typeof(DataTableMap).GetMethod("GetEntity", BindingFlags.Static | BindingFlags.NonPublic); MethodInfo generic = method.MakeGenericMethod(new[] { prop.PropertyType.GetGenericArguments()[0] }); Type listGenericType = typeof(List <>); Type list = listGenericType.MakeGenericType(prop.PropertyType.GetGenericArguments()[0]); ConstructorInfo ci = list.GetConstructor(new Type[] { }); var listEntities = ci.Invoke(new object[] { }); for (int i = 0; i < dataRows.Length; i++) { var obj = generic.Invoke(null, new object[] { dataRows[i], dataTables, convertToPrimitive, parentObj, false }); listEntities.GetType().GetMethod("Add").Invoke(listEntities, new[] { obj }); } prop.SetValue(parentObj, listEntities, null); } } } }
/// <summary> /// Extension method of datatable that return a list of entity objects. /// </summary> /// <typeparam name="TEntity">Type of the new entity.</typeparam> /// <param name="dataTable">Datatable that contain the data to be converted.</param> /// <param name="convertToPrimitive">Expecific class that define convertion to the diferents primitive types.</param> /// <returns>An IList of the new entity.</returns> public static IList <TEntity> MapToEntity <TEntity>(this DataTable dataTable, ConvertToPrimitive convertToPrimitive = null) where TEntity : class { return(MapToEntity <TEntity>(dataTable, null, null, false)); }
private static void GetOneToOneEntity <TEntity>(DataTable[] dataTables, ConvertToPrimitive convertToPrimitive, TEntity parentObj, bool oneToOneRelationRequired) { var type = typeof(TEntity); var propertiesOneToOne = type.GetProperties().Where(p => !p.GetCustomAttributes(typeof(NotMapped), true).Any() && p.GetCustomAttributes(typeof(OneToOneRelation), true).Any()); var propertiesNames = type.GetProperties().Where(p => !p.GetCustomAttributes(typeof(NotMapped), true).Any() && p.GetCustomAttributes(typeof(ColumnName), true).Any()); var propertiesNamesObj = type.GetProperties().Where(p => !p.GetCustomAttributes(typeof(NotMapped), true).Any() && !p.GetCustomAttributes(typeof(OneToOneRelation), true).Any() && !p.GetCustomAttributes(typeof(OneToManyRelation), true).Any() && !p.GetCustomAttributes(typeof(ColumnName), true).Any()); if (propertiesOneToOne != null && propertiesOneToOne.Any()) { foreach (var prop in propertiesOneToOne) { var oneToOneAttrs = prop.GetCustomAttributes(typeof(OneToOneRelation), true); if (oneToOneAttrs.Count() > 1) { throw new System.InvalidOperationException(string.Format("Property {0} contains a duplicate attribute", prop.Name)); } OneToOneRelation attr = oneToOneAttrs.Single() as OneToOneRelation; DataTable datatableOneToOne; if (oneToOneRelationRequired || attr.Required) { var datat = dataTables.Where(dt => string.Equals(dt.TableName, attr.TableName, StringComparison.OrdinalIgnoreCase)); if (!datat.Any()) { throw new ArgumentNullException(string.Format("Required Datatable was not found for the property {0} with an OneToOneRelation attribute (DataTable:{1})", prop.Name, attr.TableName)); } datatableOneToOne = datat.First(); } else { datatableOneToOne = dataTables.Where(dt => string.Equals(dt.TableName, attr.TableName, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); } if (datatableOneToOne != null && datatableOneToOne.Rows.Count > 0) { PropertyInfo propertyParentKey = null; Dictionary <string, PropertyInfo> propertyParentKeys = new Dictionary <string, PropertyInfo>(); if (!string.IsNullOrWhiteSpace(attr.ParentKey)) { propertyParentKey = SearchPropertyParent(propertiesNames, propertiesNamesObj, attr.ParentKey); } else if (attr.ParentKeys != null && attr.ParentKeys.Any()) { foreach (var key in attr.ParentKeys) { var resul = SearchPropertyParent(propertiesNames, propertiesNamesObj, key); propertyParentKeys.Add(key, resul); } } else { throw new ArgumentException("One to one relational attributes are required"); } Func <DataRow, bool> funcOneToOne = null; if (!string.IsNullOrWhiteSpace(attr.SiblingKey) && !string.IsNullOrWhiteSpace(attr.ParentKey)) { if (propertyParentKey == null) { throw new ArgumentException(string.Format("One to one relational attributes are required, ParentKey ({0}) property was not found", attr.ParentKey)); } funcOneToOne = (r) => { if (r.Table.Columns.Contains(attr.SiblingKey)) { return(string.Equals(r[attr.SiblingKey].ToString(), propertyParentKey.GetValue(parentObj, null).ToString(), StringComparison.OrdinalIgnoreCase)); } else { throw new ArgumentException(string.Format("One to one relational attributes are required, SiblingKey ({0}) column was not found", attr.SiblingKey)); } }; } else if (attr.SiblingKeys != null && attr.SiblingKeys.Any() && propertyParentKeys != null && propertyParentKeys.Any() && !propertyParentKeys.Any(p => p.Value == null) && attr.SiblingKeys.Count() == propertyParentKeys.Count()) { funcOneToOne = (r) => { bool resul = false; for (int i = 0; i < attr.SiblingKeys.Length; i++) { if (propertyParentKeys.TryGetValue(attr.ParentKeys[i], out propertyParentKey)) { if (r.Table.Columns.Contains(attr.SiblingKeys[i])) { resul = string.Equals(r[attr.SiblingKeys[i]].ToString(), propertyParentKey.GetValue(parentObj, null).ToString(), StringComparison.OrdinalIgnoreCase); } else { throw new ArgumentException(string.Format("One to one relational attributes are required, SiblingKey ({0}) column was not found", attr.SiblingKeys[i])); } } else { throw new ArgumentException("One to one relational attributes must match"); } if (!resul) { break; } } return(resul); }; } else { throw new ArgumentException("One to one relational attributes are required"); } var dataRows = datatableOneToOne.Select().Where(funcOneToOne); if (dataRows.Count() > 1) { throw new System.InvalidOperationException("Only one row must match in an One to One Relation"); } var dataRow = dataRows.SingleOrDefault(); if ((oneToOneRelationRequired || attr.Required) && dataRow == null) { throw new NullReferenceException("One to one relational row is required"); } else if (dataRow == null) { continue; } MethodInfo method = typeof(DataTableMap).GetMethod("GetEntity", BindingFlags.Static | BindingFlags.NonPublic); MethodInfo generic = method.MakeGenericMethod(new[] { prop.PropertyType }); var obj = generic.Invoke(null, new object[] { dataRow, dataTables, convertToPrimitive, parentObj, oneToOneRelationRequired }); prop.SetValue(parentObj, obj, null); } else if (oneToOneRelationRequired || attr.Required) { throw new ArgumentException("One to one relational table is required"); } } } }