Ejemplo n.º 1
0
        static void DoSave(IEntity entity, SaveBehaviour behaviour)
        {
            var mode = entity.IsNew ? SaveMode.Insert : SaveMode.Update;

            var asEntity = entity as Entity;

            if (mode == SaveMode.Update && (asEntity._ClonedFrom?.IsStale == true) && AnyOpenTransaction())
            {
                throw new InvalidOperationException("This " + entity.GetType().Name + " instance in memory is out-of-date. " +
                                                    "A clone of it is already updated in the transaction. It is not allowed to update the same instance multiple times in a transaction, because then the earlier updates would be overwriten by the older state of the instance in memory. \r\n\r\n" +
                                                    @"BAD: 
Database.Update(myObject, x=> x.P1 = ...); // Note: this could also be nested inside another method that's called here instead.
Database.Update(myObject, x=> x.P2 = ...);

GOOD: 
Database.Update(myObject, x=> x.P1 = ...);
myObject = Database.Reload(myObject);
Database.Update(myObject, x=> x.P2 = ...);");
            }

            if (EntityManager.IsImmutable(entity))
            {
                throw new ArgumentException("An immutable record must be cloned before any modifications can be applied on it. Type=" +
                                            entity.GetType().FullName + ", Id=" + entity.GetId() + ".");
            }

            var dataProvider = GetProvider(entity);

            if (!IsSet(behaviour, SaveBehaviour.BypassValidation))
            {
                EntityManager.RaiseOnValidating(entity as Entity, EventArgs.Empty);
                entity.Validate();
            }
            else if (!dataProvider.SupportValidationBypassing())
            {
                throw new ArgumentException(dataProvider.GetType().Name + " does not support bypassing validation.");
            }

            #region Raise saving event

            if (!IsSet(behaviour, SaveBehaviour.BypassSaving))
            {
                var savingArgs = new System.ComponentModel.CancelEventArgs();
                EntityManager.RaiseOnSaving(entity, savingArgs);

                if (savingArgs.Cancel)
                {
                    Cache.Current.Remove(entity);
                    return;
                }
            }
            #endregion

            if (!IsSet(behaviour, SaveBehaviour.BypassLogging) && !(entity is IApplicationEvent) && Config.Get <bool>("Log.Record.Application.Events", defaultValue: true))
            {
                ApplicationEventManager.RecordSave(entity, mode);
            }

            dataProvider.Save(entity);

            if (mode == SaveMode.Update && asEntity?._ClonedFrom != null && AnyOpenTransaction())
            {
                asEntity._ClonedFrom.IsStale = true;
                asEntity.IsStale             = false;
            }

            if (mode == SaveMode.Insert)
            {
                EntityManager.SetSaved(entity);
            }

            Cache.Current.Remove(entity);

            if (Transaction.Current != null)
            {
                Transaction.Current.TransactionCompleted += (s, e) => { Cache.Current.Remove(entity); }
            }
            ;

            if (DbTransactionScope.Root != null)
            {
                DbTransactionScope.Root.OnTransactionCompleted(() => Cache.Current.Remove(entity));
            }

            if (!(entity is IApplicationEvent))
            {
                OnUpdated(new EventArgs <IEntity>(entity));
            }

            if (!IsSet(behaviour, SaveBehaviour.BypassSaved))
            {
                EntityManager.RaiseOnSaved(entity, new SaveEventArgs(mode));
            }

            // OnSaved event handler might have read the object again and put it in the cache, which would
            // create invalid CachedReference objects.
            Cache.Current.Remove(entity);
        }