// gets the current RK values (including the modifications) internal object[] GetCurrentRKValues() { List <object> values = new List <object>(); var currentValues = PropertyAccessor.GetValues(this); foreach (var column in NodeMap.SortedRKColumns) { var columnZ = column.ID.ColumnZ; values.Add(currentValues[columnZ - 1]); } return(values.ToArray()); }
internal static Result <T> InsertGo <T>(Assembly client, DbRow row, bool identityInsert, ConnectBy connectBy) where T : DbRow { var name = Text.NotAvailable; try { var connectable = GetInsertBody <T>(client, row, identityInsert, connectBy, Text.Method.InsertGo, ref name); var result = connectable.Go <T>(); if (result.RowCount > 0) { PropertyAccessor.SetValues(row, PropertyAccessor.GetValues(result.First())); row.SetStatus(DbRowStatus.Loaded); // has rowversion & it is not RK if (row.HasNonRKRowversion) { Crud.ReloadGo <T>(client, row, false, connectBy, true); } else { // rowversion column is null: var map = DbMapping.TryGetNodeMap(row); if (map.HasRowversion && row.GetRowversionValue() == null) { row.SetStatus(DbRowStatus.Faulted); } else { row.SetStatus(DbRowStatus.Loaded); } } } result.FinalizeCrud(); return(result); } catch (QueryTalkException) { throw; } catch (System.Exception ex) { throw Crud.ClrException(ex, name, Text.Method.InsertGo); } }
private static List <JsonProperty> ReflectClass(Type type) { QueryTalkException exception; Type clrType; bool cached = false; List <JsonProperty> jsonCacheValue; cached = Cache.JsonCache.TryGetValue(type, out jsonCacheValue); if (!cached) { jsonCacheValue = new List <JsonProperty>(); var properties = type.GetReadableProperties(); var ix = 0; var valid = false; foreach (var property in properties) { var clrTypeMatch = Mapping.CheckClrCompliance(property.PropertyType, out clrType, out exception); if (clrTypeMatch != Mapping.ClrTypeMatch.ClrMatch) { continue; } if (!cached) { jsonCacheValue.Add(new JsonProperty(property.Name, clrType, PropertyAccessor.Create(type, property))); } ++ix; valid = true; } if (!valid) { throw new QueryTalkException("JsonConverter.ToJson<T>", QueryTalkExceptionType.InvalidDataClass, String.Format("type = {0}", type), Text.Method.ToJson); } Cache.JsonCache[type] = jsonCacheValue; } return(jsonCacheValue); }
internal object GetOriginalRowversionValue() { if (NodeMap.RowversionColumn == null) { return(null); } object value; var columnZ = NodeMap.RowversionColumn.ID.ColumnZ; if (_originalValues != null && _originalValues.TryGetValue(columnZ, out value)) { return(value); } else { return(PropertyAccessor.GetValues(this)[columnZ - 1]); } }
private static List <IPropertyAccessor> _GetDbRowsGetters(bool withRowID, Type type, PropertyInfo[] properties) { List <IPropertyAccessor> getters = new List <IPropertyAccessor>(); foreach (var property in properties) { getters.Add(PropertyAccessor.Create(type, property)); } if (withRowID) { Cache.IRowAccessors[type] = getters; } else { Cache.PropertyAccessors[type] = getters; } return(getters); }
internal object[] GetOriginalRKValues() { List <object> values = new List <object>(); var currentValues = PropertyAccessor.GetValues(this); foreach (var column in NodeMap.SortedRKColumns) { object value; var columnZ = column.ID.ColumnZ; if (_originalValues != null && _originalValues.TryGetValue(columnZ, out value)) { values.Add(value); } else { values.Add(currentValues[columnZ - 1]); } } return(values.ToArray()); }
// anticipated: // Row has a rowversion column. internal object GetRowversionValue() { var columnZ = NodeMap.RowversionColumn.ID.ColumnZ; return(PropertyAccessor.GetValues(this)[columnZ - 1]); }
// 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; } }
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; } }
internal static IEnumerable <T> PackRows <T>(IEnumerable source) where T : new() { if (source == null) { return(null); } Type targetType = typeof(T); Type sourceType = null; foreach (var row in source) { if (row == null) { continue; } sourceType = row.GetType(); break; } if (sourceType == null) { return(null); } TryCheckClassType(targetType); TryCheckClassType(sourceType); var sourceProperties = sourceType.GetReadableProperties(); var targetProperties = targetType.GetWritableProperties(); if (targetProperties.Length == 0) { throw new QueryTalkException("ClassConverter.TryCheckClassType", QueryTalkExceptionType.InvalidPack, String.Format("type = {0}", targetType), Text.Method.Pack); } if (sourceProperties.Length == 0) { throw new QueryTalkException("ClassConverter.TryCheckClassType", QueryTalkExceptionType.InvalidPack, String.Format("type = {0}", sourceType), Text.Method.Pack); } var sourceGetters = new List <IPropertyAccessor>(); var targetGetters = new List <IPropertyAccessor>(); bool match = false; Type clrType; QueryTalkException exception; var numberOfPropertiesUsed = 0; foreach (var targetProperty in targetProperties) { var clrTypeMatch = Mapping.CheckClrCompliance(targetProperty.PropertyType, out clrType, out exception); if (clrTypeMatch != Mapping.ClrTypeMatch.ClrMatch) { continue; } var sourceProperty = sourceProperties.Where(p => p.Name == targetProperty.Name).FirstOrDefault(); if (sourceProperty != null) { if (Common.GetClrType(sourceProperty.PropertyType) != Common.GetClrType(targetProperty.PropertyType)) { throw new QueryTalkException("ClassConverter.ToClass", QueryTalkExceptionType.PackPropertyMismatch, String.Format("target property name = {0}{1} target property type = {2}{1} source property type = {3}", targetProperty.Name, Environment.NewLine, targetProperty.PropertyType, sourceProperty.PropertyType), Text.Method.Pack); } match = true; sourceGetters.Add(PropertyAccessor.Create(sourceType, sourceProperty)); targetGetters.Add(PropertyAccessor.Create(targetType, targetProperty)); ++numberOfPropertiesUsed; } } if (!match) { throw new QueryTalkException("ClassConverter.TryCheckClassType", QueryTalkExceptionType.InvalidPack, String.Format("target type = {0}{1} source type = {2}", targetType, Environment.NewLine, sourceType), Text.Method.Pack); } var rows = new HashSet <T>(); foreach (var sourceRow in source) { if (sourceRow == null) { continue; } var targetRow = new T(); for (int i = 0; i < numberOfPropertiesUsed; i++) { var value = sourceGetters[i].GetValue(sourceRow); targetGetters[i].SetValue(targetRow, value); } rows.Add(targetRow); } return(rows); }
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)); }
private static SubResult ProcessPackage_InsertRows <T>(Assembly client, IEnumerable <T> package, NodeMap map, ConnectBy connectBy, Nullable <bool> identityInsert) where T : DbRow { if (package.Count() == 0) { return(new SubResult()); } PassChainer cpass; List <ParameterArgument> args = new List <ParameterArgument>(); var view = ViewConverter.ConvertDbRowData(package, false, true); var columns = map.GetInsertableColumns(true).Select(a => new Column(a.Name)).ToArray(); if (map.HasIdentity) { var identityPK = map.TryGetIdentityPK(); if (identityInsert == false) { var delta = ((IRow)package.First()).RowID; args.Add(view); args.Add(delta); // @Delta args.Add(identityPK.Name.Part1); // @Identity args.Add(new Column(Designer.IsNull( // ISNULL(MAX(@Identity), 0) Designer.Max(Designer.Identifier("1", identityPK.Name.Part1)), 0))); args.Add(new Column(String.Format("[1].[{0}] - @Delta + @LastID + 1", Text.Reserved.QtRowIDColumnName).E())); args.Add(map.Name); // @Table args.Add(columns); // @Columns args.Add(map.GetColumns(1)); // @AllColumns args.Add(map.BuildSelfRelation(1, 2).E()); // @On cpass = _insertRowsIntoIdentityProc.Pass(args.ToArray()); } else { args.Add(ViewConverter.ConvertDbRowData(package, false, true)); // #Rows args.Add(map.Name); // @Table args.Add(columns); // @Columns args.Add(map.GetColumns(1)); // @AllColumns args.Add(map.BuildSelfRelation(1, 2).E()); // @On cpass = _identityInsertRowsProc.Pass(args.ToArray()); } } // non-identity table else { // pass arguments args.Add(ViewConverter.ConvertDbRowData(package, false, true)); // #Rows args.Add(map.Name); // @Table args.Add(columns); // @Columns args.Add(map.GetColumns(1)); // @AllColumns args.Add(map.BuildSelfRelation(1, 2).E()); // @On cpass = _insertRowsProc.Pass(args.ToArray()); } // execute cpass.SetRootMap(map.ID); var connectable = Reader.GetConnectable(client, cpass, connectBy); var result = connectable.Go <T>(); var data = result.ToList(); var computedIndexes = map.SortedComputedColumns.Select(a => a.ID.ColumnZ).ToArray(); var j = 0; foreach (var row in package) { PropertyAccessor.SetValues(row, PropertyAccessor.GetValues(data[j++]), computedIndexes); row.SetStatus(DbRowStatus.Loaded); } // all rows inserted successfully or none return(new SubResult(true, result.RowCount)); }