/// <summary> /// Returns a generated array of <see cref="DbParameter"/>s /// that should be passed in with the command. /// </summary> /// <returns></returns> protected virtual DbParameter[] CreateParameters() { // add insert/update values var ret = new List <DbParameter>(); foreach (var colmap_kvp in ModelMap.FieldMappings) { string fld = colmap_kvp.Key; DataModelColumnAttribute colmap = colmap_kvp.Value; DbParameter param = null; switch (StatementCommand) { case SqlStatement.INSERT: if (string.IsNullOrEmpty(colmap.InsertParam)) { continue; } if (colmap.IncludeOnInsert || colmap.ReturnAsOutputOnInsert) { param = Provider.DbFactory.CreateParameter(); param.ParameterName = !colmap.InsertParam.StartsWith("@") ? "@" + colmap.InsertParam : colmap.InsertParam; if (colmap.ReturnAsOutputOnInsert) { param.Direction = ParameterDirection.Output; } } break; case SqlStatement.UPDATE: if (string.IsNullOrEmpty(colmap.UpdateParam)) { continue; } bool add = true; if (!CommandBuilder.SetAllValues) { add = DataModel.ModifiedProperties.Contains(fld); } if (add) { param = Provider.DbFactory.CreateParameter(); param.ParameterName = !colmap.UpdateParam.StartsWith("@") ? "@" + colmap.UpdateParam : colmap.UpdateParam; } break; } if (param != null && ret.Find(p => p.ParameterName == param.ParameterName) == null) { if (param is SqlParameter) { ((SqlParameter)param).SqlDbType = colmap.SqlDbType; } else { param.DbType = colmap.DbType; } if (colmap.ColumnSize.HasValue) { param.Value = colmap.ColumnSize.Value; } else if (colmap.DataType == typeof(string)) { param.Size = (DataModel[fld] ?? string.Empty).ToString().Length; } if (param.Direction == ParameterDirection.Input || param.Direction == ParameterDirection.InputOutput) { param.IsNullable = colmap.IsNullable; param.Value = DataModel[fld] ?? DBNull.Value; } ret.Add(param); } } foreach (var foreignMapping_kvp in ModelMap.ForeignModelMappings) { ForeignDataModelAttribute foreignMapping = foreignMapping_kvp.Value; if (foreignMapping.TargetMemberType.IsOrInherits(typeof(IEnumerable))) { continue; } switch (StatementCommand) { case SqlStatement.INSERT: var fieldValue = DataModel.ColumnMappedValue[foreignMapping.LocalColumn]; var paramName = "@" + foreignMapping.LocalColumn; if (ret.Find(p => p.ParameterName == paramName) == null) { if (ret.Find(p => p.ParameterName == paramName) != null) { continue; } var param = Provider.DbFactory.CreateParameter(); param.ParameterName = paramName; if (param is SqlParameter) { ((SqlParameter)param).SqlDbType = foreignMapping.LocalColumnSqlDbType; } else { param.DbType = foreignMapping.LocalColumnDbType; } if (foreignMapping.LocalColumnSize.HasValue) { param.Value = foreignMapping.LocalColumnSize.Value; } else if (foreignMapping.TargetMemberType == typeof(string)) { param.Size = (fieldValue ?? string.Empty).ToString().Length; } if (param.Direction == ParameterDirection.Input || param.Direction == ParameterDirection.InputOutput) { param.IsNullable = foreignMapping.LocalColumnIsNullable; param.Value = fieldValue ?? DBNull.Value; } ret.Add(param); } break; } } // add query conditions if (Query != null) { foreach (DataModelQueryCondition <TModel> cond in Query.Conditions) { DataModelColumnAttribute fm = cond.FieldMap; if (fm == null) { switch (cond.FindFieldMappingBy) { case FieldMappingKeyType.ClrMember: fm = ModelMap[cond.EvalSubject]; break; case FieldMappingKeyType.DbColumn: fm = ModelMap.GetFieldMappingByDbColumnName(cond.EvalSubject); break; } } string paramName = string.Empty; if (fm != null) { switch (StatementCommand) { case SqlStatement.SELECT: if (string.IsNullOrEmpty(fm.SelectParam)) { continue; } paramName = fm.SelectParam; break; case SqlStatement.INSERT: if (string.IsNullOrEmpty(fm.InsertParam)) { continue; } paramName = fm.InsertParam; break; case SqlStatement.UPDATE: if (string.IsNullOrEmpty(fm.UpdateParam)) { continue; } paramName = fm.UpdateParam; break; case SqlStatement.DELETE: if (string.IsNullOrEmpty(fm.DeleteParam)) { continue; } paramName = fm.DeleteParam; break; } if (ret.Find(p => p.ParameterName == paramName) == null) { if (UsesSproc && cond.CompareOp != Compare.Equal) { throw new InvalidOperationException( "Cannot produce an ad hoc WHERE clause with a SQL Stored Procedure."); } DbParameter param = Provider.DbFactory.CreateParameter(); param.ParameterName = !paramName.StartsWith("@") ? "@" + paramName : paramName; if (param is SqlParameter) { ((SqlParameter)param).SqlDbType = fm.SqlDbType; } else { param.DbType = fm.DbType; } if (fm.ColumnSize.HasValue) { param.Value = fm.ColumnSize.Value; } else if (fm.DataType == typeof(string)) { fm.ColumnSize = (cond.CompareValue ?? string.Empty).ToString().Length; } param.IsNullable = fm.IsNullable; param.Value = cond.CompareValue ?? DBNull.Value; ret.Add(param); } } else { if (cond.CompareValue != null) { paramName = "@" + cond.EvalSubject; if (ret.Find(p => p.ParameterName == paramName) == null) { DbParameter param = Provider.DbFactory.CreateParameter(); param.ParameterName = paramName; if (param is SqlParameter) { ((SqlParameter)param).SqlDbType = DbTypeConverter.ToSqlDbType(cond.CompareValue); } else { param.DbType = DbTypeConverter.ToDbType(cond.CompareValue); } if (cond.CompareValue is string) { param.Size = ((string)cond.CompareValue).Length; } param.IsNullable = true; param.Value = cond.CompareValue; ret.Add(param); } } } } } return(ret.ToArray()); }
/// <summary> /// When implemented, loads the full object graph for the first /// <see cref="DataModel"/> that is returned from the specified /// <paramref name="query"/>, within the specified database /// <paramref name="transactionContext"/>. /// </summary> /// <param name="query"></param> /// <param name="transactionContext"></param> /// <param name="depth"></param> /// <param name="loadedModels"> /// Used for keeping recursive loading from resulting /// in infinite loops. Evaluate each loaded item from /// a database result set against this collection; if /// there is a match, use the collection item, /// otherwise use the database loaded item, deep-load /// it, and add it to this collection. /// </param> /// <returns></returns> public virtual TModel DeepLoadModel <TModel>( DataModelQuery <TModel> query, int?depth, DbTransaction transactionContext, List <DataModel> loadedModels ) where TModel : DataModel { TModel e = LoadModel(query, transactionContext); if (e == null) { return(e); } if (loadedModels == null) { loadedModels = new List <DataModel>(); } if (loadedModels.Contains(e)) { return((TModel)loadedModels[loadedModels.IndexOf(e)]); } foreach (DataModel previouslyLoadedModel in loadedModels) { if (query.GetType().IsGenericType) { Type qt = query.GetType().GetGenericArguments()[0]; if (previouslyLoadedModel.GetType().IsOrInherits(qt) && previouslyLoadedModel.Equals(e) && previouslyLoadedModel is TModel) { return((TModel)previouslyLoadedModel); } } } if (!loadedModels.Contains(e)) { loadedModels.Add(e); } foreach (var fe_kvp in e.EntityMappings.ForeignModelMappings) { if (depth == null || depth > 0) { ForeignDataModelAttribute fe = fe_kvp.Value; Type targetEntityType = fe.TargetMemberType; while (targetEntityType.IsGenericType && targetEntityType.IsOrInherits(typeof(IEnumerable))) { targetEntityType = targetEntityType.GetGenericArguments().Last(); } if (!targetEntityType.IsDataModel()) { targetEntityType = typeof(DataModel <>).MakeGenericType(targetEntityType); } Type subQueryType = typeof(DataModelQuery <>).MakeGenericType(targetEntityType); Relationship relationship = fe.Relationship; if (relationship == Relationship.ManyToMany && string.IsNullOrEmpty(fe.MappingTable)) { relationship = Relationship.OneToMany; } switch (relationship) { case Relationship.OneToOne: case Relationship.ManyToOne: IDataModelQuery subQuery = ((IDataModelQuery)Activator.CreateInstance(subQueryType)) .WhereColumn[fe.RelatedTableColumn].IsEqualTo( e.ColumnMappedValue[fe.LocalColumn]); DataModel e2 = DeepLoadModel(targetEntityType, subQuery, depth == null ? null : depth - 1, transactionContext, loadedModels); object e2o = e2; if (!fe.TargetMemberType.IsDataModel()) { e2o = (e2).Entity; } if (fe.TargetMember.MemberType == MemberTypes.Field) { ((FieldInfo)fe.TargetMember).SetValue(e.Entity, e2o); } else if (fe.TargetMember.MemberType == MemberTypes.Property) { ((PropertyInfo)fe.TargetMember).SetValue(e.Entity, e2o, new object[] {}); } break; case Relationship.OneToMany: IDataModelQuery subQuery2 = ((IDataModelQuery)Activator.CreateInstance(subQueryType)) .WhereColumn[fe.RelatedTableColumn].IsEqualTo( e.ColumnMappedValue[fe.LocalColumn]); IDataModelCollection e2c = DeepLoadModels(targetEntityType, subQuery2, depth, transactionContext, loadedModels); object e2ct = Activator.CreateInstance(fe.TargetMemberType); if (e2ct is IList) { bool de = fe.TargetMemberType.IsGenericType && fe.TargetMemberType.GetGenericArguments().Last().IsDataModel(); foreach (object e2cx in e2c) { if (de) { ((IList)e2ct).Add(e2cx); } else { object e2cx2 = ((DataModel)e2cx).Entity; ((IList)e2ct).Add(e2cx2); } } } else { e2ct = ((IList)e2c)[0]; } if (fe.TargetMember.MemberType == MemberTypes.Field) { ((FieldInfo)fe.TargetMember).SetValue(e.Entity, e2ct); } else if (fe.TargetMember.MemberType == MemberTypes.Property) { ((PropertyInfo)fe.TargetMember).SetValue(e.Entity, e2ct, new object[] {}); } break; case Relationship.ManyToMany: if (!fe.TargetMemberType.IsOrInherits(typeof(IList))) { throw new InvalidCastException( "Cannot apply ManyToMany binding to a non-IList property."); } Type tleft = fe.DeclaringType; Type tleftEntity = tleft; while (tleftEntity.IsDataModelWrapper(true)) { if (tleftEntity.BaseType != (typeof(DataModel <>)).BaseType) { tleftEntity = tleftEntity.BaseType; } else { tleftEntity = tleftEntity.GetGenericArguments()[0]; } } Type tright = (fe.TargetMemberType.IsGenericType && !fe.TargetMemberType.IsDataModel() && fe.TargetMemberType.IsOrInherits(typeof(IList))) ? fe.TargetMemberType.GetGenericArguments()[0] : fe.TargetMemberType; Type trightEntity = tright; if (!tright.IsDataModel()) { tright = typeof(DataModel <>).MakeGenericType(tright); } Type mapType = typeof(DataModelMap.RuntimeMappingTable <,>) .MakeGenericType( // left side of mapping table fe.TargetMember.DeclaringType, // right side tright); var mapObj = (DataModel)Activator.CreateInstance(mapType); mapObj.EntityMappings.TableMapping.Schema = fe.MappingTableSchema ?? ProviderDefaults.DefaultSchema; mapObj.EntityMappings.TableMapping.Table = fe.MappingTable ?? (string.Compare(trightEntity.Name, tleftEntity.Name) == -1 ? trightEntity.Name + tleftEntity.Name : tleftEntity.Name + trightEntity.Name); DataModelColumnAttribute mapLeftCol = mapObj.EntityMappings.FieldMappings["LeftColumn"]; mapLeftCol.ColumnName = fe.LocalColumn; mapLeftCol.DbType = e.EntityMappings .GetFieldMappingByDbColumnName(fe.LocalColumn).DbType; mapLeftCol.TargetMemberType = e.EntityMappings .GetFieldMappingByDbColumnName(fe.LocalColumn).TargetMemberType; Type mapQueryType = typeof(DataModelQuery <>).MakeGenericType(new[] { mapType }); var mapQuery = (IDataModelQuery)Activator.CreateInstance(mapQueryType); mapQuery.WhereColumn[fe.LocalColumn].IsEqualTo( e.ColumnMappedValue[fe.LocalColumn]); IDataModelCollection mapdes = LoadModels(mapType, mapQuery, transactionContext); var mappedDEs = new DataModelCollection <DataModel>(); foreach (DataModel de in mapdes) // de is a MappingTable<L,R> { var mappedDEQuery = (IDataModelQuery) Activator.CreateInstance(typeof(DataModelQuery <>) .MakeGenericType(targetEntityType)); mappedDEQuery.WhereColumn[fe.RelatedTableColumn] .IsEqualTo(de.ColumnMappedValue[fe.RelatedTableColumn]); DataModel mappedDE = DeepLoadModel(targetEntityType, mappedDEQuery, depth == null ? null : depth - 1, transactionContext, loadedModels); if (mappedDE != null) { mappedDEs.Add(mappedDE); } } Type mmtargtype = fe.TargetMemberType; var mmtargcol = (IList)Activator.CreateInstance(fe.TargetMemberType); Type mapdeType = null; foreach (DataModel mapde in mappedDEs) { if (mapdeType == null) { mapdeType = mapde.GetType(); } object deinst = mapde; if (mmtargtype.IsGenericType && !mmtargtype.GetGenericArguments()[0].IsDataModel()) { deinst = mapde.Entity; } mmtargcol.Add(deinst); } if (fe.TargetMember is FieldInfo) { ((FieldInfo)fe.TargetMember).SetValue(e, mmtargcol); } else if (fe.TargetMember is PropertyInfo) { ((PropertyInfo)fe.TargetMember).SetValue( e.Entity, mmtargcol, new object[] {}); } break; } } } foreach (var field_kvp in e.EntityMappings.FieldMappings) { DataModelColumnAttribute field = field_kvp.Value; if (field.IsForeignKey && field.ForeignKeyMapping.AssignToMember != null) { LoadMember(e, field, field_kvp.Key, transactionContext, loadedModels); } } return(e); }