// Depending on whether we're to-be-inserted or were retrieved from a query, // returns the appropriate StoreCtx from the PrincipalContext that we should use for // all StoreCtx-related operations. // Returns null if no context has been set yet. internal StoreCtx GetStoreCtxToUse() { if (_ctx == null) { Debug.Assert(this.unpersisted == true); return(null); } if (this.unpersisted) { return(_ctx.ContextForType(this.GetType())); } else { return(_ctx.QueryCtx); } }
public void Save(PrincipalContext context) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "Principal", "Entering Save(Context)"); // Make sure we're not disposed or deleted. CheckDisposedOrDeleted(); // Make sure we're not a fake principal CheckFakePrincipal(); // We must have a PrincipalContext to save into. This should always be the case, unless we're unpersisted // and they never set a PrincipalContext. if (context == null) { Debug.Assert(this.unpersisted == true); throw new InvalidOperationException(SR.NullArguments); } if (context.ContextType == ContextType.Machine || _ctx.ContextType == ContextType.Machine) { throw new InvalidOperationException(SR.SaveToNotSupportedAgainstMachineStore); } // If the user is trying to save to the same context we are already set to then just save the changes if (context == _ctx) { Save(); return; } // If we already have a context set on this object then make sure the new // context is of the same type. if (context.ContextType != _ctx.ContextType) { Debug.Assert(this.unpersisted == true); throw new InvalidOperationException(SR.SaveToMustHaveSamecontextType); } StoreCtx originalStoreCtx = GetStoreCtxToUse(); _ctx = context; // Call the appropriate operation depending on whether this is an insert or update StoreCtx newStoreCtx = GetStoreCtxToUse(); Debug.Assert(newStoreCtx != null); // since we know this.ctx isn't null Debug.Assert(originalStoreCtx != null); // since we know this.ctx isn't null if (this.unpersisted) { // We have an unpersisted principal so we just want to create a principal in the new store. GlobalDebug.WriteLineIf(GlobalDebug.Info, "Principal", "Save(context): inserting new principal of type {0} using {1}", this.GetType(), newStoreCtx.GetType()); Debug.Assert(newStoreCtx == _ctx.ContextForType(this.GetType())); newStoreCtx.Insert(this); this.unpersisted = false; // once we persist, we're no longer in the unpersisted state } else { // We have a principal that already exists. We need to move it to the new store. GlobalDebug.WriteLineIf(GlobalDebug.Info, "Principal", "Save(context): Moving principal of type {0} using {1}", this.GetType(), newStoreCtx.GetType()); // we are now saving to a new store so this principal is unpersisted. this.unpersisted = true; // If the user has modified the name save away the current name so // if the move succeeds and the update fails we will move the item back to the original // store with the original name. bool nameModified = _nameChanged == LoadState.Changed; string previousName = null; if (nameModified) { string newName = _name; _ctx.QueryCtx.Load(this, PropertyNames.PrincipalName); previousName = _name; this.Name = newName; } newStoreCtx.Move(originalStoreCtx, this); try { this.unpersisted = false; // once we persist, we're no longer in the unpersisted state newStoreCtx.Update(this); } catch (System.SystemException e) { try { GlobalDebug.WriteLineIf(GlobalDebug.Error, "Principal", "Save(context):, Update Failed (attempting to move back) Exception {0} ", e.Message); if (nameModified) { this.Name = previousName; } originalStoreCtx.Move(newStoreCtx, this); GlobalDebug.WriteLineIf(GlobalDebug.Info, "Principal", "Move back succeeded"); } catch (System.SystemException deleteFail) { // The move back failed. Just continue we will throw the original exception below. GlobalDebug.WriteLineIf(GlobalDebug.Error, "Principal", "Save(context):, Move back Failed {0} ", deleteFail.Message); } if (e is System.Runtime.InteropServices.COMException) { throw ExceptionHelper.GetExceptionFromCOMException((System.Runtime.InteropServices.COMException)e); } else { throw; } } } _ctx.QueryCtx = newStoreCtx; // so Updates go to the right StoreCtx }