public CodeToDataBaseMergeCollection GetDatabase_Diff(Type tableType, CodeToDataBaseMergeCollection str = null, List <Type> createdTables = null) { str = str ?? new CodeToDataBaseMergeCollection(_repository); if (tableType.GetCustomAttribute <ExcludeFromAbstract>() != null || _alreadyControlled.Any(x => x == tableType)) { return(str); } _repository.CreateSchema(tableType); tableType = tableType.GetActualType(); _alreadyControlled.Add(tableType); createdTables = createdTables ?? new List <Type>(); if (createdTables.Any(x => x == tableType) || tableType.GetPrimaryKey() == null) { return(str); } if (CodeToDataBaseMergeCollection.ExecutedData.ContainsKey(tableType.FullName + _repository.DataBaseTypes.ToString())) { return(str); } createdTables.Add(tableType); var table = _repository.GetColumnSchema(tableType); var tableName = tableType.TableName(); var props = DeepCloner.GetFastDeepClonerProperties(tableType).Where(x => x.CanRead && !x.ContainAttribute <ExcludeFromAbstract>()); var codeToDataBaseMerge = new CodeToDataBaseMerge() { Object_Type = tableType }; var isPrimaryKey = ""; if (!IsValidName(tableName.Name)) { throw new EntityException(tableName.Name + " is not a valid Name for the current provider " + _repository.DataBaseTypes); } if (!table.Values.Any()) { codeToDataBaseMerge.Sql = new StringBuilder($"CREATE TABLE {tableName.GetName(_repository.DataBaseTypes)} ("); foreach (var prop in props.Where(x => (x.GetDbTypeByType(_repository.DataBaseTypes) != null || !x.IsInternalType || x.ContainAttribute <JsonDocument>() || x.ContainAttribute <XmlDocument>()) && !x.ContainAttribute <ExcludeFromAbstract>()).GroupBy(x => x.Name).Select(x => x.First()) .OrderBy(x => x.ContainAttribute <PrimaryKey>() ? null : x.Name)) { if (!prop.IsInternalType && !prop.ContainAttribute <JsonDocument>() && !prop.ContainAttribute <XmlDocument>()) { if (!str.Any(x => x.Object_Type == prop.PropertyType.GetActualType()) && createdTables.All(x => x != prop.PropertyType.GetActualType())) { GetDatabase_Diff(prop.PropertyType, str, createdTables); } continue; } isPrimaryKey = prop.ContainAttribute <PrimaryKey>() ? prop.GetPropertyName() : isPrimaryKey; var foreignKey = prop.GetCustomAttribute <ForeignKey>(); var dbType = prop.GetDbTypeByType(_repository.DataBaseTypes); var propName = string.Format("[{0}]", prop.GetPropertyName()); codeToDataBaseMerge.Sql.Append(propName + " "); if (!IsValidName(prop.GetPropertyName())) { throw new Exception(prop.GetPropertyName() + " is not a valid Name for the current provider " + _repository.DataBaseTypes); } if (!prop.ContainAttribute <PrimaryKey>() || _repository.DataBaseTypes == DataBaseTypes.Mssql) { codeToDataBaseMerge.Sql.Append(dbType + " "); } if (foreignKey != null && createdTables.All(x => x != foreignKey.Type)) { GetDatabase_Diff(foreignKey.Type, str, createdTables); } if (prop.ContainAttribute <PrimaryKey>()) { if (prop.PropertyType.IsNumeric() && prop.GetCustomAttribute <PrimaryKey>().AutoGenerate) { codeToDataBaseMerge.Sql.Append(_repository.DataBaseTypes == DataBaseTypes.Mssql ? "IDENTITY(1,1) NOT NULL," : (_repository.DataBaseTypes == DataBaseTypes.Sqllight ? " Integer PRIMARY KEY AUTOINCREMENT," : " BIGSERIAL PRIMARY KEY,")); } else { codeToDataBaseMerge.Sql.Append(_repository.DataBaseTypes == DataBaseTypes.Mssql ? "NOT NULL," : " " + dbType + " PRIMARY KEY,"); } continue; } if (foreignKey != null) { var key = propName + "-" + tableName.GetName(_repository.DataBaseTypes); if (!str.Keys.ContainsKey(key)) { str.Keys.Add(key, new Tuple <string, ForeignKey>(tableName.GetName(_repository.DataBaseTypes), foreignKey)); } } codeToDataBaseMerge.Sql.Append((Nullable.GetUnderlyingType(prop.PropertyType) != null || prop.PropertyType == typeof(string)) && !prop.ContainAttribute <NotNullable>() ? " NULL," : " NOT NULL,"); } if (str.Keys.Any() && _repository.DataBaseTypes == DataBaseTypes.Sqllight) { while (str.Keys.Any(x => x.Value.Item1 == tableName.Name)) { var key = str.Keys.FirstOrDefault(x => x.Value.Item1 == tableName.Name); var type = key.Value.Item2.Type.GetActualType(); var keyPrimary = type.GetPrimaryKey().GetPropertyName(); var tb = type.TableName(); codeToDataBaseMerge.Sql.Append("FOREIGN KEY(" + key.Key.Split('-')[0] + ") REFERENCES " + tb.GetName(_repository.DataBaseTypes) + "(" + keyPrimary + "),"); str.Keys.Remove(key.Key); } } if (!string.IsNullOrEmpty(isPrimaryKey) && _repository.DataBaseTypes == DataBaseTypes.Mssql) { codeToDataBaseMerge.Sql.Append(" CONSTRAINT [PK_" + tableName.Name + "] PRIMARY KEY CLUSTERED"); codeToDataBaseMerge.Sql.Append(" ([" + isPrimaryKey + "] ASC"); codeToDataBaseMerge.Sql.Append(")"); codeToDataBaseMerge.Sql.Append("WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]"); codeToDataBaseMerge.Sql.Append(") ON [PRIMARY]"); } else { if (_repository.DataBaseTypes == DataBaseTypes.Sqllight) { codeToDataBaseMerge.Sql = new StringBuilder(codeToDataBaseMerge.Sql.ToString().TrimEnd(',')); } codeToDataBaseMerge.Sql.Append(")"); } str.Add(codeToDataBaseMerge); } else { foreach (var prop in props.Where(x => (x.GetDbTypeByType(_repository.DataBaseTypes) != null || !x.IsInternalType) && !x.ContainAttribute <ExcludeFromAbstract>()).GroupBy(x => x.Name).Select(x => x.First()) .OrderBy(x => x.ContainAttribute <PrimaryKey>() ? null : x.Name)) { if (prop.ContainAttribute <ForeignKey>()) { GetDatabase_Diff(prop.GetCustomAttribute <ForeignKey>().Type, str, createdTables); } var propType = prop.PropertyType; if (prop.ContainAttribute <Stringify>() || prop.ContainAttribute <DataEncode>() || prop.ContainAttribute <ToBase64String>() || prop.ContainAttribute <JsonDocument>() || prop.ContainAttribute <XmlDocument>()) { propType = typeof(string); } var modify = prop.IsInternalType || prop.ContainAttribute <JsonDocument>() || prop.ContainAttribute <XmlDocument>() ? (_repository.DataBaseTypes == DataBaseTypes.PostgreSql ? table.Get(prop.GetPropertyName().ToLower()) : table.Get(prop.GetPropertyName())) : null; if (modify != null) { if (_repository.DataBaseTypes != DataBaseTypes.Sqllight && !(prop.GetDbTypeListByType(_repository.DataBaseTypes).Any(x => x.ToLower().Contains(modify.DataType.ToLower()))) && _repository.DataBaseTypes != DataBaseTypes.PostgreSql) { var constraine = Properties.Resources.DropContraine .Replace("@tb", $"'{tableName.Name}'").Replace("@col", $"'{prop.GetPropertyName()}'") .Replace("@schema", $"'{tableName.Schema ?? ""}'") .Replace("@TableName", "@" + counter++) .Replace("@ColumnName", "@" + counter++) .Replace("@fullName", "@" + counter++) .Replace("@DROP_COMMAND", "@" + counter++) .Replace("@FOREIGN_KEY_NAME", "@" + counter++); codeToDataBaseMerge.Sql.Append(constraine); codeToDataBaseMerge.Sql.Append($"\nALTER TABLE {tableName.GetName(_repository.DataBaseTypes)} ALTER COLUMN [{prop.GetPropertyName()}] {prop.GetDbTypeByType(_repository.DataBaseTypes)} {((Nullable.GetUnderlyingType(propType) != null || propType == typeof(string)) && !prop.ContainAttribute<NotNullable>() ? " NULL" : " NOT NULL")}"); } else { if (!(prop.GetDbTypeListByType(_repository.DataBaseTypes).Any(x => x.ToLower().Contains(modify.DataType.ToLower()))) && _repository.DataBaseTypes == DataBaseTypes.PostgreSql) { codeToDataBaseMerge.Sql.Append($"\nALTER TABLE {tableName.GetName(_repository.DataBaseTypes)} ALTER COLUMN [{prop.GetPropertyName()}] TYPE {prop.GetDbTypeByType(_repository.DataBaseTypes)}, ALTER COLUMN [{prop.GetPropertyName()}] SET DEFAULT {Querys.GetValueByTypeSTRING(MethodHelper.ConvertValue(null, propType), _repository.DataBaseTypes)};"); } } } else if (!prop.IsInternalType && !prop.ContainAttribute <JsonDocument>() && !prop.ContainAttribute <XmlDocument>()) { GetDatabase_Diff(prop.PropertyType, str, createdTables); } else { codeToDataBaseMerge.Sql.Append(string.Format("\nALTER TABLE {0} ADD " + (_repository.DataBaseTypes == DataBaseTypes.PostgreSql ? "COLUMN" : "") + " [{1}] {2} {3} DEFAULT {4};", tableName.GetName(_repository.DataBaseTypes), prop.GetPropertyName(), prop.GetDbTypeByType(_repository.DataBaseTypes), (Nullable.GetUnderlyingType(propType) != null || propType == typeof(string)) && !prop.ContainAttribute <NotNullable>() ? " NULL" : " NOT NULL", Querys.GetValueByTypeSTRING(MethodHelper.ConvertValue(null, propType), _repository.DataBaseTypes))); } } } var colRemove = new CodeToDataBaseMerge() { Object_Type = tableType }; // Now lets clean the table and remove unused columns foreach (var col in table.Values.Where(x => !props.Any(a => string.Equals(x.ColumnName, a.GetPropertyName(), StringComparison.CurrentCultureIgnoreCase) && (a.GetDbTypeByType(_repository.DataBaseTypes) != null || (!a.IsInternalType || a.ContainAttribute <JsonDocument>() || a.ContainAttribute <XmlDocument>())) && !a.ContainAttribute <ExcludeFromAbstract>()))) { if (_repository.DataBaseTypes != DataBaseTypes.Sqllight) { if (_repository.DataBaseTypes == DataBaseTypes.Mssql) { var constraine = Properties.Resources.DropContraine .Replace("@tb", $"'{tableName.Name}'") .Replace("@col", $"'{col.ColumnName}'") .Replace("@schema", $"'{tableName.Schema ?? ""}'") .Replace("@TableName", "@" + counter++) .Replace("@ColumnName", "@" + counter++) .Replace("@fullName", "@" + counter++) .Replace("@DROP_COMMAND", "@" + counter++) .Replace("@FOREIGN_KEY_NAME", "@" + counter++); colRemove.Sql.Append(constraine); } colRemove.Sql.Append(string.Format("\nALTER TABLE {0} DROP COLUMN IF EXISTS [{1}];", tableName.GetName(_repository.DataBaseTypes), col.ColumnName)); } else { colRemove.Sql.Append(string.Format("DROP TABLE IF exists [{0}_temp];\nCREATE TABLE [{0}_temp] AS SELECT {1} FROM [{0}];", tableName.Name, string.Join(",", table.Values.ToList().FindAll(x => props.Any(a => string.Equals(x.ColumnName, a.GetPropertyName(), StringComparison.CurrentCultureIgnoreCase) && (a.GetDbTypeByType(_repository.DataBaseTypes) != null || !a.IsInternalType) && !a.ContainAttribute <ExcludeFromAbstract>())).Select(x => x.ColumnName)))); colRemove.Sql.Append(string.Format("DROP TABLE [{0}];\n", tableName.Name)); colRemove.Sql.Append(string.Format("ALTER TABLE [{0}_temp] RENAME TO [{0}]; ", tableName.Name)); } colRemove.DataLoss = true; } str.Add(colRemove); foreach (var prop in props.Where(x => !x.IsInternalType && !x.ContainAttribute <JsonDocument>() && !x.ContainAttribute <XmlDocument>() && !x.ContainAttribute <XmlDocument>() && !x.ContainAttribute <ExcludeFromAbstract>()).GroupBy(x => x.Name).Select(x => x.First())) { var type = prop.PropertyType.GetActualType(); if (type.GetPrimaryKey() != null) { GetDatabase_Diff(type, str, createdTables); } } str.Add(codeToDataBaseMerge); return(str); }
public T ConvertValue <T>(object itemToConvert) { return(MethodHelper.ConvertValue <T>(itemToConvert)); }
internal static List <string> DeleteAbstract(ICustomRepository repository, object o, bool save = false) { var type = o.GetType().GetActualType(); var props = FastDeepCloner.DeepCloner.GetFastDeepClonerProperties(type); var table = "[" + type.GetCustomAttribute <Table>()?.Name ?? type.Name + "]"; var primaryKey = MethodHelper.GetPrimaryKey(o as IDbEntity); var primaryKeyValue = MethodHelper.ConvertValue <long>(primaryKey.GetValue(o)); if (primaryKeyValue <= 0) { return(new List <string>()); } var sql = new List <string>() { "DELETE " + table + Querys.Where(repository.GetDataBaseType() == DataBaseTypes.Sqllight).Column(primaryKey.GetPropertyName()).Equal(primaryKeyValue).Execute() }; foreach (var prop in props.Where(x => !x.IsInternalType && x.GetCustomAttribute <IndependentData>() == null && x.GetCustomAttribute <ExcludeFromAbstract>() == null)) { var value = prop.GetValue(o); if (value == null) { continue; } var subSql = new List <string>(); var propType = prop.PropertyType.GetActualType(); var insertBefore = props.Any(x => x.GetCustomAttribute <ForeignKey>()?.Type == propType); if (FastDeepCloner.DeepCloner.GetFastDeepClonerProperties(propType).All(x => x.GetCustomAttribute <ForeignKey>()?.Type != type)) { if (!insertBefore) { continue; } } if (value is IList) { foreach (var item in value as IList) { subSql.AddRange(DeleteAbstract(repository, item)); } } else { subSql.AddRange(DeleteAbstract(repository, value)); } if (insertBefore) { sql.InsertRange(sql.Count - 1, subSql); } else { sql.AddRange(subSql); } } if (!save) { return(sql); } try { repository.CreateTransaction(); // begin deleting all object that refer to the requasted object for (var i = sql.Count - 1; i >= 0; i--) { var cmd = repository.GetSqlCommand(sql[i]); cmd.ExecuteNonQuery(); } repository.Commit(); } catch (Exception e) { repository.Rollback(); throw e; } return(sql); }
internal static T LoadChildren <T>(T item, ICustomRepository repository, bool onlyFirstLevel = false, List <string> classes = null, List <string> ignoreList = null, Dictionary <long, List <string> > pathLoaded = null, string parentProb = null, long id = 0) where T : class { if (pathLoaded == null) { pathLoaded = new Dictionary <long, List <string> >(); } switch (item) { case null: return(null); case IList _: foreach (var tItem in (IList)item) { var entity = tItem as IDbEntity; if (entity == null) { continue; } LoadChildren(entity, repository, onlyFirstLevel, classes, ignoreList, pathLoaded, parentProb, entity.Id); } break; default: if ((item as IDbEntity) == null) { return(item); } (item as IDbEntity)?.ClearPropertChanges(); var props = FastDeepCloner.DeepCloner.GetFastDeepClonerProperties(item.GetType()); id = (item as IDbEntity).Id; foreach (var prop in props.Where(x => !x.IsInternalType && !x.ContainAttribute <ExcludeFromAbstract>())) { var path = string.Format("{0}.{1}", parentProb ?? "", prop.Name).TrimEnd('.').TrimStart('.'); var propCorrectPathName = path?.Split('.').Length >= 2 ? string.Join(".", path.Split('.').Reverse().Take(2).Reverse()) : path; if (classes != null && classes.All(x => x != propCorrectPathName)) { continue; } if (ignoreList != null && ignoreList.Any(x => x == propCorrectPathName)) { continue; } var propValue = prop.GetValue(item); if (propValue != null) { continue; } if (pathLoaded.ContainsKey(id) && pathLoaded[id].Any(x => x == path)) { continue; } if (!pathLoaded.ContainsKey(id)) { pathLoaded.Add(id, new List <string>() { path }); } else if (pathLoaded[id].All(x => x != path)) { pathLoaded[id].Add(path); } var propertyName = prop.Name; if (path?.Split('.').Length >= 2) { propertyName = string.Join(".", path.Split('.').Reverse().Take(3).Reverse()) + "." + parentProb.Split('.').Last() + "." + propertyName; } var ttype = prop.PropertyType.GetActualType(); var key = props.FirstOrDefault(x => x.ContainAttribute <ForeignKey>() && x.GetCustomAttribute <ForeignKey>().Type == ttype); if (key == null) { var column = DeepCloner.GetFastDeepClonerProperties(ttype).FirstOrDefault(x => x.ContainAttribute <ForeignKey>() && x.GetCustomAttribute <ForeignKey>().Type == item.GetType()); var primaryKey = MethodHelper.GetPrimaryKey(item as IDbEntity); if (column == null || primaryKey == null) { continue; } var keyValue = primaryKey.GetValue(item).ConvertValue <long?>(); if (!keyValue.HasValue) { continue; } var result = GetByColumn(keyValue.Value, column.Name, repository, prop.PropertyType); prop.SetValue(item, result); if (result != null && !onlyFirstLevel) { LoadChildren(result, repository, onlyFirstLevel, classes, ignoreList, pathLoaded, propertyName, id); } (item as IDbEntity)?.ClearPropertChanges(); } else { var keyValue = MethodHelper.ConvertValue <long?>(key.GetValue(item)); if (!keyValue.HasValue) { continue; } var result = GetSqlById(keyValue.Value, repository, prop.PropertyType); prop.SetValue(item, result); if (result != null && !onlyFirstLevel) { LoadChildren(result, repository, onlyFirstLevel, classes, ignoreList, pathLoaded, propertyName, id); } (item as IDbEntity)?.ClearPropertChanges(); } } break; } return(item); }
internal static long SaveObject(ICustomRepository repository, InterFace.IDbEntity o, bool isIndependentData = false, bool commit = false) { repository.CreateTransaction(); try { var updateOnly = o.State == ItemState.Changed; o.State = ItemState.Added;// reset State var props = DeepCloner.GetFastDeepClonerProperties(o.GetType()); var primaryKey = MethodHelper.GetPrimaryKey(o); var availableColumns = repository.ObjectColumns(o.GetType()); var objectRules = o.GetType().GetCustomAttribute <Rule>(); var tableName = o.GetType().GetCustomAttribute <Table>()?.Name ?? o.GetType().Name; object dbTrigger = null; if (objectRules != null && !CachedIDbRuleTrigger.ContainsKey(o.GetType())) { dbTrigger = Activator.CreateInstance(objectRules.RuleType) as object; CachedIDbRuleTrigger.Add(o.GetType(), dbTrigger); } else if (objectRules != null) { dbTrigger = CachedIDbRuleTrigger[o.GetType()]; } if (primaryKey == null) { return(0); } var value = primaryKey.GetValue(o).ConvertValue <long?>(); if (value <= 0) { value = null; } else if (value.HasValue && !updateOnly) { var data = Select(repository, o.GetType(), Querys.Where(repository.GetDataBaseType() == DataBaseTypes.Sqllight).Column(primaryKey.GetPropertyName()).Equal(value.Value).ToQueryItem).Rows.FirstOrDefault(); if (data != null) { o.Merge(data.ToObject(o.GetType()) as InterFace.IDbEntity); } } if (!updateOnly) { dbTrigger?.GetType().GetMethod("BeforeSave").Invoke(dbTrigger, new List <object>() { repository, o }.ToArray()); // Check the Rule before save } o.State = ItemState.Added; // reset State var sql = "UPDATE [" + (o.GetType().GetCustomAttribute <Table>()?.Name ?? o.GetType().Name) + "] SET "; var cols = props.Where(x => availableColumns.FindByPrimaryKey <bool>(x.GetPropertyName()) && x.IsInternalType && x.GetCustomAttribute <ExcludeFromAbstract>() == null && x.GetCustomAttribute <PrimaryKey>() == null); if (!value.HasValue) { sql = "INSERT INTO [" + tableName + "](" + string.Join(",", cols.Select(x => "[" + x.GetPropertyName() + "]")) + ") Values("; sql += string.Join(",", cols.Select(x => "@" + x.GetPropertyName())) + ");"; sql += repository.GetDataBaseType() == DataBaseTypes.Sqllight ? " select last_insert_rowid();" : " SELECT IDENT_CURRENT('" + tableName + "');"; } else { sql += string.Join(",", cols.Select(x => "[" + x.GetPropertyName() + "]" + " = @" + MethodHelper.GetPropertyName(x))); sql += Querys.Where(repository.GetDataBaseType() == DataBaseTypes.Sqllight).Column(primaryKey.GetPropertyName()).Equal(value).Execute(); } var cmd = repository.GetSqlCommand(sql); foreach (var col in cols) { var v = col.GetValue(o); if (col.ContainAttribute <ForeignKey>() && MethodHelper.ConvertValue <long?>(v) == 0) { var ob = props.FirstOrDefault(x => x.PropertyType == col.GetCustomAttribute <ForeignKey>().Type); var obValue = ob?.GetValue(o) as InterFace.IDbEntity; var independentData = ob?.GetCustomAttribute <IndependentData>() != null; if (obValue != null) { v = MethodHelper.ConvertValue <long>(MethodHelper.GetPrimaryKey(obValue).GetValue(obValue)) <= 0 ? SaveObject(repository, obValue, independentData) : MethodHelper.ConvertValue <long>(MethodHelper.GetPrimaryKey(obValue).GetValue(obValue)); } } repository.AddInnerParameter(cmd, col.GetPropertyName(), v, repository.GetSqlType(col.PropertyType)); } if (!value.HasValue) { value = MethodHelper.ConvertValue <long>(repository.ExecuteScalar(cmd)); } else { repository.ExecuteNonQuery(cmd); } if (updateOnly) { return(value.Value); } dbTrigger?.GetType().GetMethod("AfterSave").Invoke(dbTrigger, new List <object>() { repository, o, value.Value }.ToArray()); // Check the Rule before save primaryKey.SetValue(o, value); foreach (var prop in props.Where(x => !x.IsInternalType && x.GetCustomAttribute <ExcludeFromAbstract>() == null)) { var independentData = prop.GetCustomAttribute <IndependentData>() != null; var type = prop.PropertyType.GetActualType(); var oValue = prop.GetValue(o); if (oValue == null) { continue; } if (oValue is IList) { foreach (var item in (IList)oValue) { if (DeepCloner.GetFastDeepClonerProperties(item.GetType()).Any(x => x.GetCustomAttribute <ForeignKey>()?.Type == o.GetType())) { DeepCloner.GetFastDeepClonerProperties(item.GetType()).First(x => x.GetCustomAttribute <ForeignKey>()?.Type == o.GetType()).SetValue(item, value); } var res = SaveObject(repository, item as InterFace.IDbEntity, independentData); var foreignKey = FastDeepCloner.DeepCloner.GetFastDeepClonerProperties(o.GetType()).FirstOrDefault(x => x.GetCustomAttribute <ForeignKey>()?.Type == type); if (foreignKey == null || MethodHelper.ConvertValue <long>(foreignKey.GetValue(o)) > 0) { continue; } foreignKey.SetValue(o, res); o.State = ItemState.Changed; } } else { if (DeepCloner.GetFastDeepClonerProperties(oValue.GetType()).Any(x => x.GetCustomAttribute <ForeignKey>()?.Type == o.GetType())) { DeepCloner.GetFastDeepClonerProperties(oValue.GetType()).First(x => x.GetCustomAttribute <ForeignKey>()?.Type == o.GetType()).SetValue(oValue, value); } var res = SaveObject(repository, oValue as InterFace.IDbEntity, independentData); var foreignKey = FastDeepCloner.DeepCloner.GetFastDeepClonerProperties(o.GetType()).FirstOrDefault(x => x.GetCustomAttribute <ForeignKey>()?.Type == type); if (foreignKey == null || MethodHelper.ConvertValue <long>(foreignKey.GetValue(o)) > 0) { continue; } foreignKey.SetValue(o, res); o.State = ItemState.Changed; } } if (o.State == ItemState.Changed) // a change has been made outside the function Save { SaveObject(repository, o, false); } if (!commit) { return(value.Value); } repository.Commit(); return(value.Value); } catch (Exception e) { repository.Rollback(); throw e; } }