/// <summary> /// Creates a <see cref="DataTable"/> object /// with columns matching the field mappings /// for this object. This is just a schema /// export. /// </summary> /// <returns></returns> public DataTable ToDataTable() { string tableName = DataModelContext.EntityMappings.TableMapping.Table; if (!string.IsNullOrEmpty(DataModelContext.EntityMappings.TableMapping.Schema) && DataModelContext.EntityMappings.TableMapping.Schema != "dbo") { string schema = DataModelContext.EntityMappings.TableMapping.Schema; if (!schema.EndsWith(".")) { schema += "."; } tableName = schema + tableName; } var dt = new DataTable(tableName); foreach (var field_kvp in DataModelContext.EntityMappings.FieldMappings) { DataModelColumnAttribute field = field_kvp.Value; DataColumn dc; try { dc = new DataColumn(field.ColumnName, field.TargetMemberType); } catch (NotSupportedException) { dc = new DataColumn(field.ColumnName); } dt.Columns.Add(dc); } return(dt); }
/// <summary> /// Gets or sets the value identified by the specified /// <paramref name="key"/>, which corresponds to the /// mapped database column name. /// </summary> /// <param name="key"></param> /// <returns></returns> public object this[string key] { get { foreach (var field_kvp in Mapping.FieldMappings) { DataModelColumnAttribute field = field_kvp.Value; if (field.ColumnName == null) { field.ColumnName = field_kvp.Key; } if (field.ColumnName.ToLower() == key.ToLower()) { return(DataModel[field_kvp.Key]); } } if (DataModel["field:" + key] != null) { return(DataModel["field:" + key]); } throw new ArgumentException("Field mapping not found"); } set { foreach (var field_kvp in Mapping.FieldMappings) { DataModelColumnAttribute field = field_kvp.Value; if (field.ColumnName.ToLower() == key.ToLower()) { DataModel[field_kvp.Key] = value; return; } } var attr = new DataModelColumnAttribute(key) { DbType = DbTypeConverter.ToDbType(value.GetType()) }; Mapping.FieldMappings.Add("field:" + key, attr); DataModel["field:" + key] = value; } }
/// <summary> /// Prepares the /// data to propagate to or from the <see cref="Entity"/> before /// the Entity is retrieved or before data changes are made and/or saved. /// </summary> /// <param name="syncTo"></param> public override void SynchronizeFields(SyncTo syncTo) { if (Type.IsDataModel() && Type == GetUnwrappedType(Type)) { return; } switch (syncTo) { case SyncTo.FieldMappedData: foreach (var field_kvp in EntityMappings.FieldMappings) { DataModelColumnAttribute field = field_kvp.Value; // todo: optimize with cached Action<T> // see: http://msmvps.com/blogs/jon_skeet/archive/2008/08/09/making-reflection-fly-and-exploring-delegates.aspx if (field.TargetMember is FieldInfo) { object val = ((FieldInfo)field.TargetMember).GetValue(Entity); object dval = this[field.TargetMember.Name]; if (((dval == null) != (val == null)) || (dval != null && !dval.Equals(val))) { this[field.TargetMember.Name] = val; } } else if (field.TargetMember is PropertyInfo) { object val = ((PropertyInfo)field.TargetMember).GetValue(Entity, new object[] {}); if (val != null && !DataModelMap.TypeIsFieldMappable(val.GetType())) { if (DataModelMap.MapItems.ContainsKey(val.GetType()) && DataModelMap.GetEntityMapping(val.GetType()).PrimaryKeyColumns.Length == 1) { var map = DataModelMap.GetEntityMapping(val.GetType()); if (val is DataModel) { val = ((DataModel)val).ColumnMappedValue[ ((DataModel)val).EntityMappings.PrimaryKeyColumns[0]]; } else { val = val.GetType().GetProperty( map.PrimaryKeyColumns[0]).GetValue(val, new object[] { }); } } } object dval = InnerData.ContainsKey(field.TargetMember.Name) ? this[field.TargetMember.Name] : null; if (((dval == null) != (val == null)) || (dval != null && !dval.Equals(val))) { if (this.ModelData.ContainsKey(field.TargetMember.Name)) { this[field.TargetMember.Name] = val; } else { var mapping = EntityMappings[field.TargetMember.Name]; if (mapping != null) { var name = mapping.TargetMember.Name; if (this.ModelData.ContainsKey(name)) { this[name] = val; } else if (this.ModelData.ContainsKey("field:" + mapping.ColumnName)) { this["field:" + mapping.ColumnName] = val; } } } } } } break; case SyncTo.ClrMembers: foreach (var field_kvp in EntityMappings.FieldMappings) { DataModelColumnAttribute field = field_kvp.Value; // todo: optimize with cached Action<T> // see: http://msmvps.com/blogs/jon_skeet/archive/2008/08/09/making-reflection-fly-and-exploring-delegates.aspx if (field.TargetMember is FieldInfo) { object clrval = ((FieldInfo)field.TargetMember).GetValue(Entity); object dicval = this[field.TargetMember.Name]; if (((clrval == null) != (dicval == null)) || (dicval != null && !dicval.Equals(clrval))) { ((FieldInfo)field.TargetMember).SetValue( Entity, this[field.TargetMember.Name]); } } else if (field.TargetMember is PropertyInfo) { if (DataModelMap.TypeIsFieldMappable(field.TargetMemberType)) { object propval = ((PropertyInfo)field.TargetMember).GetValue(Entity, new object[] {}); object dicval = this[field.TargetMember.Name]; if (dicval == DBNull.Value) { dicval = null; } if (((dicval == null) != (propval == null)) || (dicval != null && !dicval.Equals(propval))) { ((PropertyInfo)field.TargetMember).SetValue( Entity, dicval, new object[] {}); } } else { // todo maybe: assign loaded entity? } } } break; } }
private void ExecuteFieldMapBehaviors() { // Auto-infer IsIdentity if no field is declared as primary key // and no field is declared as identity and one member is named // "ID" and that member is an int or a long. bool hasPkOrIdent = false; DataModelColumnAttribute idFieldMapping = null; string typename = null; foreach (var field_kvp in FieldMappings) { var field = field_kvp.Value; if (!field.IsForeignKey) { if ((field.IsIdentity && field.IsIdentityDefined) || (field.IsPrimaryKey && field.IsPrimaryKeyDefined)) { hasPkOrIdent = true; } if (typename == null) { typename = field.TargetMember.DeclaringType.Name.ToLower(); } var propname = field.TargetMember.Name.ToLower(); if (propname == "id" || propname == typename + "id" || propname == typename + "_id") { idFieldMapping = field; } } } if (!hasPkOrIdent && idFieldMapping != null && (idFieldMapping.DbType == DbType.Int32 || idFieldMapping.DbType == DbType.Int64)) { idFieldMapping.IsIdentity = true; } // Auto-infer a dictionary entry placeholder for foreign entity mappings // with no referenced foreign key column foreach (var fk in ForeignModelMappings) { //if (fk.Value.TargetMemberType.IsOrInherits(typeof(IEnumerable))) continue; var tmt = GetEntityType(fk.Value.TargetMemberType); var ttmap = GetEntityMapping(tmt); var ff = ttmap != null ? ttmap.GetFieldMappingByDbColumnName(fk.Value.RelatedTableColumn) : null; if (FieldMappings.ToList().Exists(p => p .Value.ColumnName.ToLower() == fk.Value.LocalColumn.ToLower())) { continue; } var fm = new DataModelColumnAttribute(); if (ff != null) { ff.CopyDeltaTo(fm); fm.ColumnName = fk.Value.LocalColumn; fm.DbType = fk.Value.LocalColumnDbType; fm.SqlDbType = fk.Value.LocalColumnSqlDbType; fm.ColumnSize = fk.Value.LocalColumnSize; fm.IsNullable = fk.Value.LocalColumnIsNullable; fm.TargetMember = fk.Value.TargetMember; fm.TargetMemberType = fk.Value.TargetMemberType; fm.IsPrimaryKey = false; fm.IsIdentity = false; FieldMappings.Add("field:" + fk.Value.LocalColumn, fm); } _FieldMapBehaviorsExecuted = true; } // predetermine NULLables based on CLR nullability foreach (var field_kvp in FieldMappings) { var field = field_kvp.Value; if (!field.IsNullableDefined) { var memtype = field.TargetMemberType; bool nullable = !memtype.IsValueType; if (memtype.IsGenericType && memtype.GetGenericTypeDefinition() == typeof(Nullable <>)) { memtype = memtype.GetGenericArguments()[0]; nullable = true; } field.IsNullable = (memtype.IsValueType || memtype == typeof(string)) && nullable && !field.IsPrimaryKey; } } }
private void LoadFieldMappingAttributes() { var hierarchy = new List <Type>(); var t = this.EntityType; while (t != typeof(DataModel) && t != typeof(object)) { hierarchy.Insert(0, t); t = t.BaseType; } // walk up hierarchy foreach (var type in hierarchy) { var pis = type.GetProperties(); var fis = type.GetFields(); var mis = new Dictionary <MemberInfo, Type>(); foreach (var fi in fis) { mis.Add(fi, fi.FieldType); // fee fi fo fum } foreach (var pi in pis) { mis.Add(pi, pi.PropertyType); } foreach (var mi_kvp in mis) { var mi = mi_kvp.Key; var miType = mi_kvp.Value; var attrs = mi.GetCustomAttributes(typeof(DataModelColumnAttribute), false); if (!TypeIsFieldMappable(miType)) { if (attrs.Length > 0) { throw new InvalidAttributeException("Cannot apply a " + typeof(DataModelColumnAttribute).Name + " to a member having a custom or complex type. " + "Use " + typeof(ForeignDataModelAttribute).Name + ".", mi.Name, (Attribute)attrs[0]); } continue; } foreach (DataModelColumnAttribute attr in attrs) { attr.TargetMember = mi; attr.TargetMemberType = miType; if (string.IsNullOrEmpty(attr.ColumnName)) { attr.ColumnName = mi.Name; attr.IsColumnNameInferred = true; } if (FieldMappings.ContainsKey(mi.Name) && !attr.ClearBaseObjectMapping) { attr.CopyDeltaTo(FieldMappings[mi.Name]); } else { FieldMappings[mi.Name] = attr; } var fm = FieldMappings[mi.Name]; if (fm.DataType == null) { var def = miType; Type[] genargs; if (def.IsGenericType && (genargs = def.GetGenericArguments()).Length == 1) { def = genargs[0]; } try { fm.DbType = DbTypeConverter.ToDbType(def); } catch { } } } } } if ((FieldMappings.Count == 0 && TableMapping.PropertyLoadBehavior == InferProperties.OnlyAttributedOrAllIfNoneHaveAttributes) || TableMapping.PropertyLoadBehavior == InferProperties.NotIgnored) { foreach (var type in hierarchy) { var pis = type.GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance); var fis = type.GetFields(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance); var mis = new Dictionary <MemberInfo, Type>(); foreach (var fi in fis) { mis.Add(fi, fi.FieldType); // fee fi fo fum } foreach (var pi in pis) { mis.Add(pi, pi.PropertyType); } foreach (var mi_kvp in mis) { var mi = mi_kvp.Key; if (!FieldMappings.ContainsKey(mi.Name)) { var miType = mi_kvp.Value; var ignoreAttrib = mi.GetCustomAttributes(typeof(DataModelIgnoreAttribute), false); if (ignoreAttrib != null && ignoreAttrib.Length > 0) { continue; } var gt = miType; if (!TypeIsFieldMappable(gt)) { continue; } var attr = new DataModelColumnAttribute(mi.Name); attr.TargetMember = mi; attr.TargetMemberType = miType; FieldMappings[mi.Name] = attr; var fm = attr; if (fm.DataType == null) { var def = miType; Type[] genargs; if (def.IsGenericType && (genargs = def.GetGenericArguments()).Length == 1) { def = genargs[0]; } try { fm.DbType = DbTypeConverter.ToDbType(def); } catch { } } } } } } }