/// <summary> /// Get query that can be used to copy all wanted fields into new records. /// </summary> /// <typeparam name="TModelAbstraction">The abstraction which contains metadata for the table.</typeparam> /// <typeparam name="TModelImplementation">The implementation of the abstraction to be used as an intermediary.</typeparam> /// <param name="order">The information for the query.</param> /// <param name="clauseCallback">The method that will produce the clause for the query.</param> /// <param name="wrapInTransaction">Whether to wrap in transaction or not.</param> /// <returns><see cref="IAliasedCommandTypeDataOrder"/> containing the query, parents, and aliases.</returns> public static IAliasedCommandTypeDataOrder GetRecordCopyQuery <TModelAbstraction, TModelImplementation>(RecordCopyOrder <TModelImplementation> order, Func <RecordCopyClauseCallbackOrder, Clause> clauseCallback, bool wrapInTransaction = true) where TModelImplementation : TModelAbstraction { // Ascertain types in order to use reflection. Type abstractionType = typeof(TModelAbstraction); Type implementationType = typeof(TModelImplementation); // This dictionary gets the meta data of the abstract type. Missing some of these will cause an exception. Dictionary <Type, string> metaDataDictionary = MetaDataOperations.GetMetaDataNames(abstractionType); // Get table name from meta data. string tableName = metaDataDictionary .First(dict => dict.Key == typeof(TableNameAttribute)) .Value; // Get id set for use in filtering clause. KeyValuePair <string, object>[] idSet = order .TransferKeys .Select((r, index) => new KeyValuePair <string, object>(Clause.GenerateParameterName(), r)) .ToArray(); // Produce a dictionary that has the values pulled in from the DefaultModel supplied through parameter. // Key => Name of field which should match property name. // Value => KeyValuePair where Key => ParameterName, Value => value of property. Dictionary <string, KeyValuePair <string, object> > defaultValues = new[] { metaDataDictionary[typeof(CreatorAttribute)], metaDataDictionary[typeof(DateCreatedAttribute)], order.ParentIdName, } .Concat(order.DefaultFieldsToCopy) .Where(field => field != metaDataDictionary[typeof(IdAttribute)] && field != metaDataDictionary[typeof(UpdatorAttribute)] && field != metaDataDictionary[typeof(DateUpdatedAttribute)]) .Distinct() .ToDictionary(field => field, field => new KeyValuePair <string, object>(Clause.GenerateParameterName(), implementationType.GetProperty(field).GetValue(order.DefaultModel))); // Identify fields that should not be copied from record to record. // Use these fields to produce a list of fields not containing these fields. string[] unwantedFields = metaDataDictionary .Where(dict => dict.Key != typeof(TableNameAttribute)) .Select(dict => dict.Value) .Concat(defaultValues.Select(value => value.Key)) .Distinct() .ToArray(); string[] fieldsToCopy = abstractionType.GetProperties().Where(prop => unwantedFields.Contains(prop.Name) == false).Select(prop => prop.Name).OrderBy(field => field).ToArray(); // A collection of field names, with accompanying parameters are produced. Tuple <string, string>[] fieldParameterNameTupleCollection = defaultValues.Select(value => Tuple.Create(value.Key, value.Value.Key)).ToArray(); // Here is a callback that can be used to produce the clause that filters the records to be copied. Clause tempTableClause = clauseCallback(new RecordCopyClauseCallbackOrder(idSet.Select(id => Tuple.Create(id.Key, id.Value)), fieldParameterNameTupleCollection)); // Get the record copy query, assemble parameters, and return. ISimpleDataOrder transferQuery = Get.RecordCopyQuery(tableName, metaDataDictionary[typeof(IdAttribute)], tempTableClause, fieldParameterNameTupleCollection, fieldsToCopy); var parameters = transferQuery .Parameters .Concat(defaultValues.Select(value => value.Value)) .Concat(idSet) .OrderBy(pair => pair.Key); string query = wrapInTransaction ? SurroundQueryWithTransaction(transferQuery.Query) : transferQuery.Query; return(new AliasedCommandTypeDataOrder(query, CommandType.Text, parameters)); }
/// <summary> /// Get query that can be used to copy all wanted fields into new records. /// </summary> /// <typeparam name="TModelAbstraction">The abstraction which contains metadata for the table.</typeparam> /// <typeparam name="TModelImplementation">The implementation of the abstraction to be used as an intermediary.</typeparam> /// <param name="order">The information for the query.</param> /// <param name="wrapInTransaction">Whether to wrap in transaction or not.</param> /// <returns><see cref="IAliasedCommandTypeDataOrder"/> containing the query, parents, and aliases.</returns> public static IAliasedCommandTypeDataOrder GetRecordCopyQuery <TModelAbstraction, TModelImplementation>(RecordCopyOrder <TModelImplementation> order, bool wrapInTransaction = true) where TModelImplementation : TModelAbstraction { Type abstractionType = typeof(TModelAbstraction); Dictionary <Type, string> metaDataDictionary = MetaDataOperations.GetMetaDataNames(abstractionType); string primaryKeyFieldName = metaDataDictionary .First(dict => dict.Key == typeof(IdAttribute)) .Value; // In this case, the clause will filter out where the ParentId is the same as the current record, and then try to match any of the keys being tried for. Func <RecordCopyClauseCallbackOrder, Clause> clauseCallback = (rcccOrder) => Clause.New() .AddClause($"{order.ParentIdName} <> {rcccOrder.FieldParameterNameTupleCollection.First(tuple => tuple.Item1 == order.ParentIdName).Item2}") .AddClause($"{primaryKeyFieldName} IN ({string.Join(",", rcccOrder.Keys.Select(r => $"\r\n {r.Item1}"))}\r\n)") ; return(GetRecordCopyQuery <TModelAbstraction, TModelImplementation>(order, clauseCallback, wrapInTransaction)); }