internal DeferredSourceFactory(MetaDataMember member, CommonDataServices services) { this.member = member; this.services = services; this.refersToPrimaryKey = this.member.IsAssociation && this.member.Association.OtherKeyIsPrimaryKey; this.empty = new T[] { }; }
private bool HasAssociationChanged(MetaAssociation assoc, TrackedObject item) { if (item.Original != null && item.Current != null) { if (assoc.ThisMember.StorageAccessor.HasAssignedValue(item.Current) || assoc.ThisMember.StorageAccessor.HasLoadedValue(item.Current) ) { return(this.GetOtherItem(assoc, item.Current) != this.GetOtherItem(assoc, item.Original)); } else { object[] currentFKs = CommonDataServices.GetForeignKeyValues(assoc, item.Current); object[] originaFKs = CommonDataServices.GetForeignKeyValues(assoc, item.Original); for (int i = 0, n = currentFKs.Length; i < n; i++) { if (!object.Equals(currentFKs[i], originaFKs[i])) { return(true); } } } } return(false); }
private void Init(object connection, MappingSource mapping) { _perInstanceProviderMode = DataContext.ProviderMode; MetaModel model = mapping.GetModel(this.GetType()); this._services = new CommonDataServices(this, model); this._conflicts = new ChangeConflictCollection(); // determine provider Type providerType; if (model.ProviderType != null) { providerType = model.ProviderType; } else { throw Error.ProviderTypeNull(); } if (!typeof(IProvider).IsAssignableFrom(providerType)) { throw Error.ProviderDoesNotImplementRequiredInterface(providerType, typeof(IProvider)); } this._provider = (IProvider)Activator.CreateInstance(providerType); SetProviderMode(); this._provider.Initialize(this._services, connection); this._tables = new Dictionary <MetaTable, ITable>(); this.InitTables(this); }
private void ClearForeignKeyReferences(TrackedObject to) { foreach (var association in to.Type.Associations) { if (association.IsForeignKey) { if (association.OtherMember != null && association.OtherKeyIsPrimaryKey) { var foreignKeyValues = CommonDataServices.GetForeignKeyValues(association, to.Current); var instance = services.IdentityManager.Find(association.OtherType, foreignKeyValues); if (instance != null) { if (association.OtherMember.Association.IsMany) { var list = association.OtherMember.MemberAccessor.GetBoxedValue(instance) as IList; if (list != null && !list.IsFixedSize) { list.Remove(to.Current); ClearForeignKeysHelper(association, to.Current); } } else { association.OtherMember.MemberAccessor.SetBoxedValue(ref instance, null); ClearForeignKeysHelper(association, to.Current); } } } else { ClearForeignKeysHelper(association, to.Current); } } } }
private void Init(object connection, MappingSource mapping) { var model = mapping.GetModel(GetType()); services = new CommonDataServices(this, model); conflicts = new ChangeConflictCollection(); // determine provider if (model.ProviderType == null) { throw Error.ProviderTypeNull(); } var providerType = model.ProviderType; if (!typeof(IProvider).IsAssignableFrom(providerType)) { throw Error.ProviderDoesNotImplementRequiredInterface(providerType, typeof(IProvider)); } provider = (IProvider)Activator.CreateInstance(providerType); provider.Initialize(services, connection); tables = new Dictionary <MetaTable, ITable>(); InitTables(this); }
internal static ChangeTracker CreateChangeTracker(CommonDataServices dataServices, bool asReadOnly) { if (asReadOnly) { return(new ReadOnlyChangeTracker()); } return(new StandardChangeTracker(dataServices)); }
/// <summary> /// Clears out the foreign key values and parent object references for deleted objects on the child side of a relationship. /// For bi-directional relationships, also performs the following fixup: /// - for 1:N we remove the deleted entity from the opposite EntitySet or collection /// - for 1:1 we null out the back reference /// </summary> private void ClearForeignKeyReferences(TrackedObject to) { Debug.Assert(to.IsDeleted, "Foreign key reference cleanup should only happen on Deleted objects."); foreach (MetaAssociation assoc in to.Type.Associations) { if (assoc.IsForeignKey) { // If there is a member on the other side referring back to us (i.e. this is a bi-directional relationship), // we want to do a cache lookup to find the other side, then will remove ourselves from that collection. // This cache lookup is only possible if the other key is the primary key, since that is the only way items can be found in the cache. if (assoc.OtherMember != null && assoc.OtherKeyIsPrimaryKey) { Debug.Assert(assoc.OtherMember.IsAssociation, "OtherMember of the association is expected to also be an association."); // Search the cache for the target of the association, since // it might not be loaded on the object being deleted, and we // don't want to force a load. object[] keyValues = CommonDataServices.GetForeignKeyValues(assoc, to.Current); object cached = this._services.IdentityManager.Find(assoc.OtherType, keyValues); if (cached != null) { if (assoc.OtherMember.Association.IsMany) { // Note that going through the IList interface handles // EntitySet as well as POCO collections that implement IList // and are not FixedSize. System.Collections.IList collection = assoc.OtherMember.MemberAccessor.GetBoxedValue(cached) as System.Collections.IList; if (collection != null && !collection.IsFixedSize) { collection.Remove(to.Current); // Explicitly clear the foreign key values and parent object reference ClearForeignKeysHelper(assoc, to.Current); } } else { // Null out the other association. Since this is a 1:1 association, // we're not concerned here with causing a deferred load, since the // target is already cached (since we're deleting it). assoc.OtherMember.MemberAccessor.SetBoxedValue(ref cached, null); // Explicitly clear the foreign key values and parent object reference ClearForeignKeysHelper(assoc, to.Current); } } // else the item was not found in the cache, so there is no fixup that has to be done // We are explicitly not calling ClearForeignKeysHelper because it breaks existing shipped behavior and we want to maintain backward compatibility } else { // This is a unidirectional relationship or we have no way to look up the other side in the cache, so just clear our own side ClearForeignKeysHelper(assoc, to.Current); } } // else this is not the 1-side (foreign key) of the relationship, so there is nothing for us to do } }
internal ChangeProcessor(CommonDataServices services, DataContext context) { this._services = services; this._context = context; this._tracker = services.ChangeTracker; this._changeDirector = services.ChangeDirector; this._currentParentEdges = new EdgeMap(); this._originalChildEdges = new EdgeMap(); this._originalChildReferences = new ReferenceMap(); }
/// <summary> /// Refresh a collection of objects using the mode specified. If the refresh /// cannot be performed (for example if the object no longer exists in the /// database) an InvalidOperationException is thrown. /// </summary> /// <param name="mode">How the refresh should be performed.</param> /// <param name="entities">The collection of objects to refresh.</param> public void Refresh(RefreshMode mode, IEnumerable entities) { CheckDispose(); CheckNotInSubmitChanges(); VerifyTrackingEnabled(); if (entities == null) { throw Error.ArgumentNull("entities"); } // if the collection is a query, we need to execute and buffer, // since below we will be issuing additional queries and can only // have a single reader open. var list = entities.Cast <object>().ToList(); // create a fresh context to fetch new state from DataContext refreshContext = this.CreateRefreshContext(); foreach (object o in list) { // verify that each object in the list is an entity MetaType inheritanceRoot = _services.Model.GetMetaType(o.GetType()).InheritanceRoot; GetTable(inheritanceRoot.Type); TrackedObject trackedObject = this._services.ChangeTracker.GetTrackedObject(o); if (trackedObject == null) { throw Error.UnrecognizedRefreshObject(); } if (trackedObject.IsNew) { throw Error.RefreshOfNewObject(); } // query to get the current database values object[] keyValues = CommonDataServices.GetKeyValues(trackedObject.Type, trackedObject.Original); object freshInstance = refreshContext.Services.GetObjectByKey(trackedObject.Type, keyValues); if (freshInstance == null) { throw Error.RefreshOfDeletedObject(); } // refresh the tracked object using the new values and // the mode specified. trackedObject.Refresh(mode, freshInstance); } }
// Not implementing finalizer here because there are no unmanaged resources // to release. See http://msdnwiki.microsoft.com/en-us/mtpswiki/12afb1ea-3a17-4a3f-a1f0-fcdb853e2359.aspx // The bulk of the clean-up code is implemented in Dispose(bool) protected virtual void Dispose(bool disposing) { // Implemented but empty so that derived contexts can implement // a finalizer that potentially cleans up unmanaged resources. if (disposing) { if (this._provider != null) { this._provider.Dispose(); this._provider = null; } this._services = null; this._tables = null; this._loadOptions = null; } }
private bool HasAssociationChanged(MetaAssociation assoc, TrackedObject item) { if (item.Original != null && item.Current != null) { if (assoc.ThisMember.StorageAccessor.HasAssignedValue(item.Current) || assoc.ThisMember.StorageAccessor.HasLoadedValue(item.Current)) { return(GetOtherItem(assoc, item.Current) != GetOtherItem(assoc, item.Original)); } var foreignKeyValues = CommonDataServices.GetForeignKeyValues(assoc, item.Current); var foreignKeyValues2 = CommonDataServices.GetForeignKeyValues(assoc, item.Original); var i = 0; for (var num = foreignKeyValues.Length; i < num; i++) { if (!object.Equals(foreignKeyValues[i], foreignKeyValues2[i])) { return(true); } } } return(false); }
private TrackedObject GetOtherItem(MetaAssociation assoc, object instance) { if (instance == null) { return(null); } object obj = null; if (assoc.ThisMember.StorageAccessor.HasAssignedValue(instance) || assoc.ThisMember.StorageAccessor.HasLoadedValue(instance)) { obj = assoc.ThisMember.MemberAccessor.GetBoxedValue(instance); } else if (assoc.OtherKeyIsPrimaryKey) { var foreignKeyValues = CommonDataServices.GetForeignKeyValues(assoc, instance); obj = services.GetCachedObject(assoc.OtherType, foreignKeyValues); } if (obj == null) { return(null); } return(tracker.GetTrackedObject(obj)); }
private TrackedObject GetOtherItem(MetaAssociation assoc, object instance) { if (instance == null) { return(null); } object other = null; // Don't load unloaded references if (assoc.ThisMember.StorageAccessor.HasAssignedValue(instance) || assoc.ThisMember.StorageAccessor.HasLoadedValue(instance) ) { other = assoc.ThisMember.MemberAccessor.GetBoxedValue(instance); } else if (assoc.OtherKeyIsPrimaryKey) { // Maybe it's in the cache, but not yet attached through reference. object[] foreignKeys = CommonDataServices.GetForeignKeyValues(assoc, instance); other = this._services.GetCachedObject(assoc.OtherType, foreignKeys); } // else the other key is not the primary key so there is no way to try to look it up return((other != null) ? this._tracker.GetTrackedObject(other) : null); }
internal StandardChangeTracker(CommonDataServices services) { this.services = services; this.items = new Dictionary <object, StandardTrackedObject>(); this.onPropertyChanging = new PropertyChangingEventHandler(this.OnPropertyChanging); }
internal StandardChangeTracker(CommonDataServices services) { this.services = services; items = new Dictionary <object, StandardTrackedObject>(); onPropertyChanging = OnPropertyChanging; }