Ejemplo n.º 1
0
        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;
            }
        }