private static void _BuildDbRowsValues(bool rkOnly, bool withRowID, NodeMap nodeMap, List <IPropertyAccessor> getters, StringBuilder sql, bool firstRow, DbRow row, object[] originalValues, ref int j, ref int gi) { int ov = 0; // original values index foreach (var column in nodeMap.SortedColumns) { if (rkOnly && !column.IsRK) { ++gi; continue; } if (j != 0) { sql.Append(Text.Comma); } var value = getters[gi].GetValue(row); value = column.TryCorrectMinWeakDatetime(value, row); AppendColumnValue(sql, value, j + 1, column.DataType, (firstRow && column.DataType.DT == DT.Sqlvariant)); ++j; ++gi; if (withRowID && column.IsRK) { if (j != 0) { sql.Append(Text.Comma); } AppendColumnValue(sql, originalValues[ov], j + 1, column.DataType, (firstRow && column.DataType.DT == DT.Sqlvariant)); ++j; ++ov; } } }
internal static object TryCorrectMinWeakDatetime(this ColumnMap column, object value, DbRow row) { if (Admin.IsDateTimeMinCorrectionOn && value != null && column.DataType.DT.IsWeakDateTime() && (DateTime)value == DateTime.MinValue && !row.SetColumns.Contains(column.ID.ColumnZ)) { // datetime: if (column.DataType.DT == DT.Datetime) { return(Common.DatetimeMinSql); } // smalldatetime: else { return(Common.DatetimeMinSql); } } else { return(value); } }
internal static Result <T> DeleteCascadeGo <T>(Assembly client, DbRow row, int maxLevels, ConnectBy connectBy) where T : DbRow { var name = Text.NotAvailable; try { if (row == null) { throw new QueryTalkException("Crud.GoDeleteCascade", QueryTalkExceptionType.ArgumentNull, "row = null", Text.Method.DeleteCascadeGo); } Crud.CheckTable(row, Text.Method.DeleteCascadeGo); CrudProcedure cached = row.NodeID.TryGetProcedure(CrudProcedureType.DeleteCascadeGo); Procedure proc; if (cached == null) { var map = DbMapping.TryGetNodeMap(row); var where = map.BuildRKPredicate(row.GetOriginalRKValues(), 0); Chainer workingProc = Designer.GetNewDesigner(Text.Method.DeleteCascadeGo, true, true) .ParamNodeColumns(row.NodeID, ColumnSelector.RK); // collect all linked nodes using GetChildren method List <NodeTree> tree = new List <NodeTree>(); ((ITable)((INode <T>)row).Node).LoadChildren(ref tree, 1, maxLevels); // loop through all leaves foreach (var node in tree.OrderByDescending(a => a.Level)) { workingProc = BuildQuery(tree, node, node, node.Level, workingProc, where, true); } // delete root row & create Procedure object proc = ((IFrom)workingProc) .From(map.Name).As(0) .Where(where) .Delete(Text.Zero) .EndProcInternal(); Cache.CrudProcedures.Add(new CrudProcedure(row.NodeID, CrudProcedureType.DeleteCascadeGo, proc)); } else { proc = cached.Procedure; } var rkValues = row.GetOriginalRKValues(); var args = new List <ParameterArgument>(); foreach (var value in rkValues) { args.Add(new ParameterArgument(new Value(value))); } var cpass = proc.Pass(args.ToArray()); cpass.SetRootMap(row.NodeID); var connectable = Reader.GetConnectable(client, row, cpass, connectBy); var result = connectable.Go(); return(new Result <T>(true, -1)); } catch (QueryTalkException) { throw; } catch (System.Exception ex) { throw Crud.ClrException(ex, name, Text.Method.DeleteCascadeGo); } }
// isSilent: // if true, then this method is used by other CRUD method (.UpdateGo/.InsertGo) which requires special treatment. internal static Result <T> ReloadGo <T>(Assembly client, DbRow row, bool forceMirroring, ConnectBy connectBy, bool isSilent = false) where T : DbRow { var name = Text.NotAvailable; try { ColumnSelector selector = forceMirroring ? ColumnSelector.All : ColumnSelector.RK; if (isSilent) { selector = ColumnSelector.RK; } if (row == null) { throw new QueryTalkException("Crud.GoReload", QueryTalkExceptionType.ArgumentNull, "row = null", Text.Method.ReloadGo); } Crud.CheckTable(row, Text.Method.ReloadGo); List <ParameterArgument> args = new List <ParameterArgument>(); var map = DbMapping.TryGetNodeMap(row); name = map.Name.Sql; if (forceMirroring) { if (!row.GetStatus().IsUpdatable()) { var arguments = map.BuildExceptionReport(row.GetOriginalRKValues(), row.GetOriginalRowversionValue()); throw new QueryTalkException("Crud.ReloadGo", QueryTalkExceptionType.InvalidMirroring, arguments, Text.Method.ReloadGo).SetObjectName(map.Name.Sql); } } object[] originalValues; if (selector == ColumnSelector.All) { if (map.HasRowversion) { originalValues = new object[] { row.GetOriginalRowversionValue() }; } else { originalValues = row.GetOriginalValues(); } } // RK selector else { originalValues = row.GetOriginalRKValues(); } for (int i = 0; i < originalValues.Length; ++i) { args.Add(new ParameterArgument(new Value(originalValues[i]))); } args.Add(map.Name); if (selector == ColumnSelector.All) { args.Add(new ParameterArgument(map.BuildOptimisticPredicate(originalValues, 1))); } else { args.Add(new ParameterArgument(map.BuildRKPredicate(originalValues, 1))); } var cpass = ReloadProc(row.NodeID, selector).Pass(args.ToArray()); cpass.SetRootMap(row.NodeID); // important! Connectable connectable = Reader.GetConnectable(client, row, cpass, connectBy); var result = connectable.Go <T>(); // success if (result.RowCount > 0) { PropertyAccessor.SetValues(row, result.First().GetOriginalValues()); row.SetStatus(DbRowStatus.Loaded); return(new Result <T>(true, 0)); } // not found else { var arguments = map.BuildExceptionReport(row.GetOriginalRKValues(), row.GetOriginalRowversionValue()); if (!isSilent) { if (forceMirroring) { throw new QueryTalkException("Crud.ReloadGo", QueryTalkExceptionType.ConcurrencyViolation, arguments, Text.Method.ReloadGo).SetObjectName(map.Name.Sql); } else { throw new QueryTalkException("Crud.ReloadGo", QueryTalkExceptionType.ReloadFailed, arguments, Text.Method.ReloadGo).SetObjectName(map.Name.Sql); } } else { row.SetStatus(DbRowStatus.Faulted); return(new Result <T>(true, 0)); } } } catch (QueryTalkException ex) { Loader.TryThrowInvalidSqlOperationException(ex, name, Text.Method.ReloadGo); throw; } catch (System.Exception ex) { var ex2 = Crud.ClrException(ex, name, Text.Method.ReloadGo); Loader.TryThrowInvalidSqlOperationException(ex2, name); throw ex2; } }
internal static View ConvertDbRowData(IEnumerable <DbRow> rows, bool rkOnly = false, bool withRowID = false) { var first = rows.Where(row => row != null).First(); var nodeMap = DbMapping.GetNodeMap(first.NodeID); if (nodeMap.ID.Equals(DB3.Default)) { DbRow.ThrowInvalidDbRowException(first.GetType()); } var rowCount = 0; var columns = new List <ViewColumnInfo>(); var type = first.GetType(); var properties = type.GetSortedWritableProperties(withRowID); var numberOfProperties = properties.Length; if (numberOfProperties == 0) { throw new QueryTalkException("ViewConverter.ToView<T>", QueryTalkExceptionType.InvalidDataClass, String.Format("data class = {0}", type)); } List <IPropertyAccessor> getters; bool cached; if (withRowID) { cached = Cache.IRowAccessors.TryGetValue(type, out getters); } else { cached = Cache.PropertyAccessors.TryGetValue(type, out getters); } if (!cached) { getters = _GetDbRowsGetters(withRowID, type, properties); } var sql = Text.GenerateSql(500) .Append(Text.Select).S(); int i = 0; i = _BuildDbRowsOuterSelect(rkOnly, withRowID, nodeMap, columns, sql, i); if (withRowID) { sql.NewLineIndent(Text.Comma); AppendColumn(sql, String.Format("CAST({0} AS [int])", Filter.DelimitNonAsterix(String.Format("{0}{1}", Text.ColumnShortName, i + 1))), Text.Reserved.QtRowIDColumnName); } sql.S() .NewLine(Text.From).S() .Append(Text.LeftBracket).S(); bool firstRow = true; foreach (var row in rows) { if (row == null) { continue; } if (!firstRow) { sql.NewLineIndent(Text.UnionAll).S() .Append(Text.Select).S(); } else { sql.NewLineIndent(Text.Select).S(); } var originalValues = row.GetOriginalRKValues(); var gi = 0; // getter index int j = 0; _BuildDbRowsValues(rkOnly, withRowID, nodeMap, getters, sql, firstRow, row, originalValues, ref j, ref gi); if (withRowID) { var value = getters[gi].GetValue(row); sql.Append(Text.Comma); AppendColumnValue(sql, value, j + 1); } firstRow = false; ++rowCount; } sql.NewLine(Text.RightBracket).S() .Append(Text.As).S() .Append(Text.DelimitedTargetAlias); return(new View(sql.ToString(), typeof(DbRow), columns.ToArray(), rowCount)); }
private static Connectable GetDeleteBody(Assembly client, DbRow row, bool forceMirroring, ConnectBy connectBy, string method, ref string name, out NodeMap map) { if (row == null) { throw new QueryTalkException("Crud", QueryTalkExceptionType.ArgumentNull, "row = null", method); } Crud.CheckTable(row, method); ColumnSelector selector = forceMirroring ? ColumnSelector.All : ColumnSelector.RK; List <ParameterArgument> args = new List <ParameterArgument>(); map = DbMapping.TryGetNodeMap(row); name = map.Name.Sql; if (forceMirroring) { if (!row.GetStatus().IsUpdatable()) { var arguments = map.BuildExceptionReport(row.GetOriginalRKValues(), row.GetOriginalRowversionValue()); throw new QueryTalkException("Crud.DeleteGo", QueryTalkExceptionType.InvalidMirroring, arguments, Text.Method.DeleteGo).SetObjectName(map.Name.Sql); } } object[] originalValues; if (selector == ColumnSelector.All) { if (map.HasRowversion) { originalValues = new object[] { row.GetOriginalRowversionValue() }; } else { originalValues = row.GetOriginalValues(); } } // RK selector else { originalValues = row.GetOriginalRKValues(); } for (int i = 0; i < originalValues.Length; ++i) { args.Add(new ParameterArgument(new Value(originalValues[i]))); } args.Add(map.Name); if (selector == ColumnSelector.All) { args.Add(new ParameterArgument(map.BuildOptimisticPredicate(originalValues, 1))); } else { args.Add(new ParameterArgument(map.BuildRKPredicate(originalValues, 1))); } var cpass = DeleteProc(row.NodeID, selector).Pass(args.ToArray()); cpass.SetRootMap(row.NodeID); // important! return(Reader.GetConnectable(client, row, cpass, connectBy)); }
private static void _BuildClassOuterSelect(Type type, ref Type clrType, ref QueryTalkException exception, List <ViewColumnInfo> columns, bool isEmpty, PropertyInfo[] properties, out List <IPropertyAccessor> getters, out int numberOfProperties, StringBuilder sqlOuter, StringBuilder sqlEmpty) { numberOfProperties = properties.Length; if (numberOfProperties == 0) { throw new QueryTalkException("ViewConverter.ToView<T>", QueryTalkExceptionType.InvalidDataClass, String.Format("data class = {0}", type)); } bool cached = Cache.PropertyAccessors.TryGetValue(type, out getters); if (!cached) { getters = new List <IPropertyAccessor>(); } NodeMap rowMap = null; bool isDbRow = type.IsDbRow(); if (isDbRow) { rowMap = DbMapping.GetNodeMap(type); if (rowMap.ID.Equals(DB3.Default)) { DbRow.ThrowInvalidDbRowException(type); } } // outer select: int i = 0; foreach (var property in properties) { string column; var clrTypeMatch = Mapping.CheckClrCompliance(property.PropertyType, out clrType, out exception); if (clrTypeMatch != Mapping.ClrTypeMatch.ClrMatch) { continue; } ViewColumnInfo columnInfo; if (isDbRow) { var rowColumn = rowMap.Columns.Where(a => a.ID.ColumnZ == i + 1).First(); column = rowColumn.Name.Part1; columnInfo = new ViewColumnInfo(column, rowColumn.DataType, rowColumn.IsNullable); columns.Add(columnInfo); } else { column = property.Name; columnInfo = new ViewColumnInfo(column, property.PropertyType, clrType); columns.Add(columnInfo); } if (i != 0) { sqlOuter.NewLineIndent(Text.Comma); sqlEmpty.Append(Text.Comma); } var dataType = Mapping.ProvideDataType(columnInfo.DataType, clrType); AppendOuterColumn(sqlOuter, dataType, i + 1, column); if (isEmpty) { AppendNullValueColumn(sqlEmpty, i + 1); } if (!cached) { getters.Add(PropertyAccessor.Create(type, property)); } ++i; } numberOfProperties = i; if (numberOfProperties == 0) { ThrowInvalidDataClassException(type); } if (!cached) { Cache.PropertyAccessors[type] = getters; } }
private static Connectable GetUpdateBody <T>(Assembly client, DbRow row, bool forceMirroring, ConnectBy connectBy, string method, ref string name, out NodeMap map) where T : DbRow { if (row == null) { throw new QueryTalkException("Crud", QueryTalkExceptionType.ArgumentNull, "row = null", method); } Crud.CheckTable(row, method); ColumnSelector selector = forceMirroring ? ColumnSelector.All : ColumnSelector.RK; List <ParameterArgument> args = new List <ParameterArgument>(); map = DbMapping.TryGetNodeMap(row); name = map.Name.Sql; if (forceMirroring) { if (!row.GetStatus().IsUpdatable()) { var arguments = map.BuildExceptionReport(row.GetOriginalRKValues(), row.GetOriginalRowversionValue()); throw new QueryTalkException("Crud.UpdateGo", QueryTalkExceptionType.InvalidMirroring, arguments, Text.Method.UpdateGo).SetObjectName(map.Name.Sql); } } object[] originalValues; if (selector == ColumnSelector.All) { if (map.HasRowversion) { originalValues = new object[] { row.GetOriginalRowversionValue() }; } else { originalValues = row.GetOriginalValues(); } } // RK selector else { originalValues = row.GetOriginalRKValues(); } for (int i = 0; i < originalValues.Length; ++i) { args.Add(new ParameterArgument(new Value(originalValues[i]))); } var currentValues = PropertyAccessor.GetValues(row); var updatableColumns = row.GetUpdatableColumns(forceMirroring); if (updatableColumns == null || updatableColumns.Length == 0) { return(null); } var valueParams = new Column[updatableColumns.Length]; int j = 0; foreach (var column in updatableColumns) { var value = new Value(currentValues[column.ID.ColumnZ - 1]); args.Add(new ParameterArgument(value)); valueParams[j] = String.Format("@v{0}", j + 1); ++j; } args.Add(map.Name); if (selector == ColumnSelector.All) { args.Add(new ParameterArgument(map.BuildOptimisticPredicate(originalValues, 1))); } else { args.Add(new ParameterArgument(map.BuildRKPredicate(originalValues, 1))); } int[] modified = updatableColumns.Select(a => a.ID.ColumnZ).ToArray(); args.Add(map.Columns .Where(a => modified.Contains(a.ID.ColumnZ)) .OrderBy(a => a.ID.ColumnZ) .Select(a => new Column(a.Name)) .ToArray()); Column[] outputColumns; Column[] selectColumns; _getColumnsWithoutRowversion(map, out outputColumns, out selectColumns); var cpass = UpdateProc <T>(map, selector, valueParams, updatableColumns, outputColumns, selectColumns).Pass(args.ToArray()); cpass.SetRootMap(row.NodeID); return(Reader.GetConnectable(client, row, cpass, connectBy)); }
internal static Async <Result <T> > UpdateGoAsync <T>(Assembly client, DbRow row, bool forceMirroring, ConnectBy connectBy, Action <Result <T> > onCompleted) where T : DbRow { var name = Text.NotAvailable; NodeMap map; Crud.CheckTable(row, Text.Method.UpdateGo); try { var connectable = GetUpdateBody <T>(client, row, forceMirroring, connectBy, Text.Method.UpdateGo, ref name, out map); // no columns to modify? if (connectable == null) { return(Async <Result <T> > .CreateDefault <T>()); } return(connectable.GoAsync <T>(result => { try { // success if (result.ReturnValue == 1) { PropertyAccessor.SetValues(row, PropertyAccessor.GetValues(result.First())); row.SetStatus(DbRowStatus.Loaded); } // concurrency violation else { if (forceMirroring) { var arguments = map.BuildExceptionReport(row.GetOriginalRKValues(), row.GetOriginalRowversionValue()); throw new QueryTalkException("Crud.UpdateGoAsync", QueryTalkExceptionType.ConcurrencyViolation, arguments, Text.Method.UpdateGoAsync).SetObjectName(map.Name.Sql); } } result.FinalizeCrud(); onCompleted?.Invoke(result); } catch (QueryTalkException) { throw; } catch (System.Exception ex) { throw Crud.ClrException(ex, name, Text.Method.InsertGoAsync); } })); } catch (QueryTalkException ex) { Loader.TryThrowInvalidSqlOperationException(ex, name, Text.Method.UpdateGo); throw; } catch (System.Exception ex) { var ex2 = Crud.ClrException(ex, name, Text.Method.UpdateGo); Loader.TryThrowInvalidSqlOperationException(ex2, name); throw ex2; } }
internal static Result <T> UpdateGo <T>(Assembly client, DbRow row, bool forceMirroring, ConnectBy connectBy) where T : DbRow { var name = Text.NotAvailable; NodeMap map; try { var connectable = GetUpdateBody <T>(client, row, forceMirroring, connectBy, Text.Method.UpdateGo, ref name, out map); // no columns to modify? if (connectable == null) { return(new Result <T>(false, 0)); } var result = connectable.Go <T>(); // success if (result.ReturnValue == 1) { PropertyAccessor.SetValues(row, PropertyAccessor.GetValues(result.First())); // has rowversion & it is not RK if (row.HasNonRKRowversion) { row.SetStatus(DbRowStatus.Loaded); Crud.ReloadGo <T>(client, row, true, connectBy, true); } else { // rowversion column is null: if (map.HasRowversion && row.GetRowversionValue() == null) { row.SetStatus(DbRowStatus.Faulted); } else { row.SetStatus(DbRowStatus.Loaded); } } result.FinalizeCrud(); return(result); } // optimistic concurrency violation else { if (forceMirroring) { var arguments = map.BuildExceptionReport(row.GetOriginalRKValues(), row.GetOriginalRowversionValue()); throw new QueryTalkException("Crud.UpdateGo", QueryTalkExceptionType.ConcurrencyViolation, arguments, Text.Method.UpdateGo).SetObjectName(map.Name.Sql); } else { result.FinalizeCrud(); return(result); } } } catch (QueryTalkException ex) { Loader.TryThrowInvalidSqlOperationException(ex, name, Text.Method.UpdateGo); throw; } catch (System.Exception ex) { var ex2 = Crud.ClrException(ex, name, Text.Method.UpdateGo); Loader.TryThrowInvalidSqlOperationException(ex2, name); throw ex2; } }
private static Connectable GetInsertBody <T>(Assembly client, DbRow row, bool identityInsert, ConnectBy connectBy, string method, ref string name) where T : DbRow { if (row == null) { throw new QueryTalkException("Crud", QueryTalkExceptionType.ArgumentNull, "row = null", method); } Crud.CheckTable(row, method); List <ParameterArgument> args = new List <ParameterArgument>(); var map = DbMapping.TryGetNodeMap(row); name = map.Name.Sql; if (!map.HasIdentity) { identityInsert = false; } var insertableColumns = map.GetInsertableColumns(row, identityInsert); Column[] outputColumns; Column[] selectColumns; _getColumnsWithoutRowversion(map, out outputColumns, out selectColumns); PassChainer cpass; if (insertableColumns.Length > 0) { var currentValues = PropertyAccessor.GetValues(row); var valueParams = new Column[insertableColumns.Length]; int j = 0; foreach (var column in insertableColumns) { var value = new Value(currentValues[column.ID.ColumnZ - 1]); value.Original = column.TryCorrectMinWeakDatetime(value.Original, row); args.Add(new ParameterArgument(value)); valueParams[j] = String.Format("@v{0}", j + 1); ++j; } args.Add(map.Name); args.Add(insertableColumns .Select(a => new Column(a.Name)) .ToArray()); cpass = InsertProc <T>(insertableColumns, valueParams, identityInsert, outputColumns, selectColumns) .Pass(args.ToArray()); } // default values: else { cpass = InsertProcDefaultValues <T>(outputColumns, selectColumns).Pass(map.Name); } cpass.SetRootMap(row.NodeID); return(Reader.GetConnectable(client, row, cpass, connectBy)); }