/// <summary>Creates a many-to-one or one-to-one relationship between two objects in the object context.</summary> /// <param name="entity">The object being attached.</param> /// <exception cref="T:System.ArgumentNullException">When the entity is null.</exception> /// <exception cref="T:System.InvalidOperationException">When the entity cannot be related to the current related end. This can occur when the association in the conceptual schema does not support a relationship between the two types.</exception> public void Attach(TEntity entity) { Check.NotNull(entity, "entity"); CheckOwnerNull(); Attach(new[] { EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext) }, false); }
public void DoWork(IRequest request) { if (String.IsNullOrEmpty(_requestContext.ResourceKey)) { throw new RequestException("Please use single resource url"); } IEntityWrapper wrapper; wrapper = EntityWrapperFactory.Create(_requestContext.ResourceKind, _requestContext); SdataTransactionResult sdTrResult = wrapper.Delete(_requestContext.ResourceKey); if (sdTrResult == null) { throw new RequestException("Entity does not exists"); } if (sdTrResult.HttpStatus == System.Net.HttpStatusCode.OK) { request.Response.StatusCode = System.Net.HttpStatusCode.OK; } else { throw new RequestException(sdTrResult.HttpMessage); } }
public void DoWork(IRequest request) { if (request.ContentType != Sage.Common.Syndication.MediaType.AtomEntry) { throw new RequestException("Atom entry content type expected"); } if (!String.IsNullOrEmpty(_requestContext.ResourceKey)) { throw new RequestException("Please use resource url"); } // read entry from stream SyncFeedEntry entry = new SyncFeedEntry(); XmlReader reader = XmlReader.Create(request.Stream); reader.MoveToContent(); entry.ReadXml(reader, ResourceKindHelpers.GetPayloadType(_requestContext.ResourceKind)); IEntityWrapper wrapper = EntityWrapperFactory.Create(_requestContext.ResourceKind, _requestContext); Document document = wrapper.GetTransformedDocument(entry.Payload, entry.SyncLinks); if (!String.IsNullOrEmpty(document.Id)) { throw new RequestException("Entity alredy exists"); } // Add Document SdataTransactionResult sdTrResult = wrapper.Add(entry.Payload, entry.SyncLinks); if (sdTrResult == null) { throw new RequestException("Entity does not exists"); //????? } if ((sdTrResult.HttpStatus == System.Net.HttpStatusCode.OK) || (sdTrResult.HttpStatus == System.Net.HttpStatusCode.Created)) { // store correlation SyncFeedEntry responseEntry = wrapper.GetFeedEntry(sdTrResult.LocalId); SyncFeed feed = new SyncFeed(); feed.FeedType = FeedType.ResourceEntry; feed.Entries.Add(responseEntry); request.Response.StatusCode = System.Net.HttpStatusCode.Created; request.Response.Serializer = new SyncFeedSerializer(); request.Response.Feed = feed; request.Response.Protocol.SendUnknownResponseHeader("Location", responseEntry.Id); request.Response.ContentType = Sage.Common.Syndication.MediaType.AtomEntry; } else { throw new RequestException(sdTrResult.HttpMessage); } }
/// <summary>Defines relationships between an object and a collection of related objects in an object context.</summary> /// <remarks> /// Loads related entities into the local collection. If the collection is already filled /// or partially filled, merges existing entities with the given entities. The given /// entities are not assumed to be the complete set of related entities. /// Owner and all entities passed in must be in Unchanged or Modified state. We allow /// deleted elements only when the state manager is already tracking the relationship /// instance. /// </remarks> /// <param name="entities">Collection of objects in the object context that are related to the source object.</param> /// <exception cref="T:System.ArgumentNullException"> entities collection is null.</exception> /// <exception cref="T:System.InvalidOperationException"> /// The source object or an object in the entities collection is null or is not in an /// <see /// cref="F:System.Data.Entity.EntityState.Unchanged" /> /// or <see cref="F:System.Data.Entity.EntityState.Modified" /> state.-or-The relationship cannot be defined based on the EDM metadata. This can occur when the association in the conceptual schema does not support a relationship between the two types. /// </exception> public void Attach(IEnumerable <TEntity> entities) { Check.NotNull(entities, "entities"); CheckOwnerNull(); IList <IEntityWrapper> wrappedEntities = new List <IEntityWrapper>(); foreach (var entity in entities) { wrappedEntities.Add(EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext)); } Attach(wrappedEntities, true); }
public void OnCollectionDeserialized(StreamingContext context) { if (_relatedEntities != null) { // We need to call this here so that the hash set will be fully constructed // ready for access. Normally, this would happen later in the process. _relatedEntities.OnDeserialization(null); _wrappedRelatedEntities = new Dictionary <TEntity, IEntityWrapper>(); foreach (TEntity entity in _relatedEntities) { _wrappedRelatedEntities.Add(entity, EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext)); } } }
internal override void Include(bool addRelationshipAsUnchanged, bool doAttach) { if (null != _wrappedRelatedEntities && null != this.ObjectContext) { List <IEntityWrapper> wrappedRelatedEntities = new List <IEntityWrapper>(_wrappedRelatedEntities.Values); foreach (IEntityWrapper wrappedEntity in wrappedRelatedEntities) { // Sometimes with mixed POCO and IPOCO, you can get different instances of IEntityWrappers stored in the IPOCO related ends // These should be replaced by the IEntityWrapper that is stored in the context IEntityWrapper identityWrapper = EntityWrapperFactory.WrapEntityUsingContext(wrappedEntity.Entity, WrappedOwner.Context); if (identityWrapper != wrappedEntity) { _wrappedRelatedEntities[(TEntity)identityWrapper.Entity] = identityWrapper; } IncludeEntity(identityWrapper, addRelationshipAsUnchanged, doAttach); } } }
public void DoWork(IRequest request) { IEntityWrapper wrapper = EntityWrapperFactory.Create(_requestContext.ResourceKind, _requestContext); SyncFeed syncFeed = wrapper.GetFeed(); request.Response.Serializer = new SyncFeedSerializer(); if (String.IsNullOrEmpty(_requestContext.ResourceKey)) { syncFeed.FeedType = FeedType.Resource; request.Response.ContentType = Sage.Common.Syndication.MediaType.Atom; } else { syncFeed.FeedType = FeedType.ResourceEntry; request.Response.ContentType = Sage.Common.Syndication.MediaType.AtomEntry; } request.Response.Feed = syncFeed; }
internal override void Include(bool addRelationshipAsUnchanged, bool doAttach) { Debug.Assert(this.ObjectContext != null, "Should not be trying to add entities to state manager if context is null"); // If we have an actual value or a key for this reference, add it to the context if (null != _wrappedCachedValue.Entity) { // Sometimes with mixed POCO and IPOCO, you can get different instances of IEntityWrappers stored in the IPOCO related ends // These should be replaced by the IEntityWrapper that is stored in the context IEntityWrapper identityWrapper = EntityWrapperFactory.WrapEntityUsingContext(_wrappedCachedValue.Entity, WrappedOwner.Context); if (identityWrapper != _wrappedCachedValue) { _wrappedCachedValue = identityWrapper; } IncludeEntity(_wrappedCachedValue, addRelationshipAsUnchanged, doAttach); } else if (DetachedEntityKey != null) { IncludeEntityKey(doAttach); } // else there is nothing to add for this relationship }
public void OnRefDeserialized(StreamingContext context) { _wrappedCachedValue = EntityWrapperFactory.WrapEntityUsingContext(_cachedValue, ObjectContext); }
/// <summary> /// Attaches an entity to the EntityReference. The given /// entity is not assumed to be the complete set of related entities. /// /// Owner and all entities passed in must be in Unchanged or Modified state. /// Deleted elements are allowed only when the state manager is already tracking the relationship /// instance. /// </summary> /// <param name="entity">The entity to attach to the EntityCollection</param> /// <exception cref="ArgumentNullException">Thrown when <paramref name="entity"/> is null.</exception> /// <exception cref="InvalidOperationException">Thrown when the entity cannot be related via the current relationship end.</exception> public void Attach(TEntity entity) { CheckOwnerNull(); EntityUtil.CheckArgumentNull(entity, "entity"); Attach(new IEntityWrapper[] { EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext) }, false); }
internal bool RemoveInternal(TEntity entity) { return(Remove(EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext), /*preserveForeignKey*/ false)); }
/// <summary>Adds an object to the collection.</summary> /// <param name="item"> /// An object to add to the collection. entity must implement /// <see /// cref="T:System.Data.Entity.Core.Objects.DataClasses.IEntityWithRelationships" /> /// . /// </param> /// <exception cref="T:System.ArgumentNullException"> entity is null.</exception> public void Add(TEntity item) { Check.NotNull(item, "item"); Add(EntityWrapperFactory.WrapEntityUsingContext(item, ObjectContext)); }
// Asynchronous called method private void Execute(NorthwindConfig config, SyncFeed feed) { #region Declarations SdataContext sdataContext; SupportedResourceKinds resource; IAppBookmarkInfoStore appBookmarkInfoStore; ICorrelatedResSyncInfoStore correlatedResSyncInfoStore; ISyncSyncDigestInfoStore syncDigestStore; GuidConverter guidConverter = new GuidConverter(); string resourceKind; string endpoint; SyncFeedDigest sourceDigest; SyncDigestInfo targetDigest; IEntityWrapper wrapper; #endregion #region init sdataContext = _parentPerformer._requestContext.SdataContext; resource = _parentPerformer._requestContext.ResourceKind; resourceKind = resource.ToString(); endpoint = _parentPerformer._requestContext.DatasetLink + resourceKind; appBookmarkInfoStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetAppBookmarkStore(sdataContext); correlatedResSyncInfoStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetCorrelatedResSyncStore(sdataContext); syncDigestStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetSyncDigestStore(sdataContext); sourceDigest = feed.Digest; targetDigest = syncDigestStore.Get(resourceKind); wrapper = EntityWrapperFactory.Create(resource, _parentPerformer._requestContext); #endregion #region process entries bool sourceIsDeleteMode; SdataTransactionResult sdTrResult; SyncState sourceState; SyncState targetState; foreach (SyncFeedEntry entry in feed.Entries) { sdTrResult = null; try { // Check whether the source entry had been deleted. // if not we expect a payload! // The variable 'sourceIsDeleteMode' holds the result of this check for later calls. if (entry.HttpMethod.Equals("DELETE", StringComparison.InvariantCultureIgnoreCase)) { sourceIsDeleteMode = true; } else if (null == entry.Payload) { throw new Exception("Payload missing."); } else { sourceIsDeleteMode = false; } // set the uuid to the payload.SyncUuid property if (!sourceIsDeleteMode) { entry.Payload.SyncUuid = entry.Uuid; } // get the source syncstate sourceState = entry.SyncState; // Look into the store to get all correlations of the uuid received from source CorrelatedResSyncInfo[] corelations = correlatedResSyncInfoStore.GetByUuid(resourceKind, new Guid[] { entry.Uuid }); if (corelations.Length == 0) { if (sourceIsDeleteMode) { // the source entry had been deleted and no correlation exists for this // entry in the target. // So we do nothing here. sdTrResult = new SdataTransactionResult(); sdTrResult.HttpStatus = HttpStatusCode.OK; sdTrResult.HttpMessage = "OK"; sdTrResult.HttpMethod = "DELETE"; sdTrResult.ResourceKind = resource; sdTrResult.Uuid = entry.Uuid; } else { // no target entry exists for the updated or added source entry. // So we add the source entry to the application and add a new correlation to the sync store. // If this operation fails we will have to set the result state to conflict. try { // add the entry to application sdTrResult = wrapper.Add(entry.Payload, entry.SyncLinks); if ((sdTrResult != null) && ((sdTrResult.HttpStatus == HttpStatusCode.OK) || (sdTrResult.HttpStatus == HttpStatusCode.Created))) { string etag = EtagServices.ComputeEtag(entry.Payload, true); ResSyncInfo resSyncInfo = new ResSyncInfo(entry.Uuid, entry.SyncState.Endpoint, entry.SyncState.Tick, etag, entry.SyncState.Stamp); CorrelatedResSyncInfo correlatedResSyncInfo = new CorrelatedResSyncInfo(sdTrResult.LocalId, resSyncInfo); // store the new correlation to the sync store correlatedResSyncInfoStore.Put(resourceKind, correlatedResSyncInfo); // update the sync digest entry if the tick of the source entry is newer than the actual tick of the target. syncDigestStore.PersistNewer(resourceKind, correlatedResSyncInfo.ResSyncInfo); } } catch (Exception e) { // in case of an unexpected error while adding a new entry to target // we create a transaction result with the state 'Conflict' sdTrResult = new SdataTransactionResult(); sdTrResult.HttpStatus = HttpStatusCode.Conflict; sdTrResult.HttpMethod = "POST"; sdTrResult.HttpMessage = e.ToString(); sdTrResult.ResourceKind = resource; sdTrResult.Uuid = entry.Uuid; } } } else { // a correlation was found for the source entry. #region update or delete try { bool doUpdate = false; //bool doDelete = false; bool isConflict = true; // set the LocalID from correlation to the entry.Payload.LocalID property // only if source had not been deleted. if (!sourceIsDeleteMode) { entry.Payload.LocalID = corelations[0].LocalId; } targetState = Helper.GetSyncState(corelations[0]); //If sourceState.endpoint = targetState.endpoint, //there is no conflict and the update must be applied //if sourceState.tick > targetState.tick. if (targetState.Endpoint.Equals(sourceState.Endpoint, StringComparison.InvariantCultureIgnoreCase)) { isConflict = false; if (sourceState.Tick > targetState.Tick) { //if (!sourceIsDeleteMode) doUpdate = true; //else // doDelete = true; } } else { SyncState sourceDigestSyncState = Helper.GetSyncState(sourceDigest, targetState.Endpoint);; SyncState targetDigestSyncState = Helper.GetSyncState(targetDigest, sourceState.Endpoint); //If targetState is contained in sourceDigest, //i.e. if sourceDigest has a digest entry E such that E.endpoint = targetState.endpoint //and E.tick >= targetState.tick, there is no conflict and the update must be applied. if (sourceDigestSyncState != null) { if (sourceDigestSyncState.Tick > targetState.Tick) { doUpdate = true; isConflict = false; } } //If sourceState is contained in targetDigest, //i.e. if targetDigest has a digest entry E such that E.endpoint = sourceState.endpoint //and E.tick >= sourceState.tick, there is no conflict and the update must be ignored //(target has the most recent version). if (targetDigestSyncState != null) { if (targetDigestSyncState.Tick > sourceState.Tick) { doUpdate = false; isConflict = false; } } //Otherwise (targetState not contained in sourceDigest, sourceState not contained in targetDigest), //there is a conflict. if ((sourceDigestSyncState == null) && (targetDigestSyncState == null)) { isConflict = true; } } //****************** Conflict **************** //In case of conflict, the target endpoint uses the following algorithm to resolve the conflict: //Let sourceEntry be the sourceDigest digest entry such that sourceEntry.endpoint = sourceState.endpoint. //Let targetEntry be the targetDigest digest entry such that targetEntry.endpoint = targetState.endpoint. //If sourceEntry .conflictPriority <> targetEntry .conflictPriority, the side with lowest priority wins. if (isConflict) { int sourceConflictPriority = Helper.GetConflictPriority(sourceDigest, sourceState.Endpoint); int targetConflictPriority = Helper.GetConflictPriority(targetDigest, targetState.Endpoint); if (sourceConflictPriority > targetConflictPriority) { doUpdate = true; } else if (sourceConflictPriority < targetConflictPriority) { doUpdate = false; } else { //Otherwise (sourceEntry .conflictPriority = targetEntry .conflictPriority), //then sourceState.stamp and targetState.stamp are compared //and the entry with the most recent timestamp wins. if (sourceState.Stamp > targetState.Stamp) { doUpdate = true; } } } ResSyncInfo resSyncInfo = new ResSyncInfo(entry.Uuid, entry.SyncState.Endpoint, entry.SyncState.Tick, "", entry.SyncState.Stamp); if (doUpdate && !sourceIsDeleteMode) { // update the entry in the application and update the sync store sdTrResult = wrapper.Update(entry.Payload, entry.SyncLinks); if ((sdTrResult != null) && (sdTrResult.HttpStatus == HttpStatusCode.OK)) { string etag = EtagServices.ComputeEtag(entry.Payload, true); resSyncInfo = new ResSyncInfo(entry.Uuid, entry.SyncState.Endpoint, entry.SyncState.Tick, etag, entry.SyncState.Stamp); CorrelatedResSyncInfo correlatedResSyncInfo = new CorrelatedResSyncInfo(sdTrResult.LocalId, resSyncInfo); correlatedResSyncInfoStore.Put(resourceKind, correlatedResSyncInfo); } } else if (!doUpdate && !sourceIsDeleteMode) { sdTrResult = new SdataTransactionResult(); sdTrResult.HttpStatus = HttpStatusCode.Conflict; sdTrResult.HttpMethod = "PUT"; sdTrResult.HttpMessage = ""; sdTrResult.ResourceKind = resource; sdTrResult.Uuid = entry.Uuid; } else if (doUpdate && sourceIsDeleteMode) { // delete the entry in the application and update the sync store // we do not support nested deletion. So only TradingAccounts and SalesOrders can be deleted. if (resource == SupportedResourceKinds.tradingAccounts || resource == SupportedResourceKinds.salesOrders) { sdTrResult = wrapper.Delete(corelations[0].LocalId); if ((sdTrResult != null) && (sdTrResult.HttpStatus == HttpStatusCode.OK)) { correlatedResSyncInfoStore.Delete(resource.ToString(), corelations[0].ResSyncInfo.Uuid); } } else { // this does not correspond to real fact, what we did at target side! sdTrResult = new SdataTransactionResult(); sdTrResult.HttpStatus = HttpStatusCode.OK; sdTrResult.HttpMessage = "OK"; sdTrResult.HttpMethod = "DELETE"; sdTrResult.ResourceKind = resource; sdTrResult.Uuid = entry.Uuid; } } else { sdTrResult = new SdataTransactionResult(); sdTrResult.HttpStatus = HttpStatusCode.Conflict; sdTrResult.HttpMessage = ""; sdTrResult.HttpMethod = "DELETE"; sdTrResult.ResourceKind = resource; sdTrResult.Uuid = entry.Uuid; } syncDigestStore.PersistNewer(resourceKind, resSyncInfo); } catch (Exception e) { sdTrResult = new SdataTransactionResult(); sdTrResult.HttpStatus = HttpStatusCode.Conflict; sdTrResult.HttpMethod = "PUT"; sdTrResult.HttpMessage = e.ToString(); sdTrResult.ResourceKind = resource; sdTrResult.Uuid = entry.Uuid; } #endregion } } catch (Exception e) { sdTrResult = new SdataTransactionResult(); sdTrResult.HttpStatus = HttpStatusCode.Conflict; sdTrResult.HttpMessage = e.ToString(); sdTrResult.ResourceKind = resource; sdTrResult.Uuid = entry.Uuid; } #region store transaction result if (sdTrResult != null) { lock (_parentPerformer._asyncStateObj) { this._parentPerformer._asyncStateObj.TransactionResults.Add(sdTrResult); } } #endregion } #endregion // Set tracking phase lock (_parentPerformer._asyncStateObj.Tracking) { _parentPerformer._asyncStateObj.Tracking.Phase = TrackingPhase.FINISH; } }
public void DoWork(IRequest request) { EntryRequestType entryRequestType; string resourceKindName; ICorrelatedResSyncInfoStore correlatedResSyncStore; bool includeDataPayloads; //?includePayloads value CorrelatedResSyncInfo[] correlatedResSyncInfos; int totalResult; #region initialization // multi or single entry request? entryRequestType = (String.IsNullOrEmpty(_requestContext.ResourceKey)) ? EntryRequestType.Multi : EntryRequestType.Single; resourceKindName = _requestContext.ResourceKind.ToString(); string tmpValue; // ?includePayloads includeDataPayloads = false; // default value, but check for settings now if (_requestContext.SdataUri.QueryArgs.TryGetValue("includePayload", out tmpValue)) { includeDataPayloads = System.Xml.XmlConvert.ToBoolean(tmpValue); } // get store to request the correlations correlatedResSyncStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetCorrelatedResSyncStore(_requestContext.SdataContext); #endregion // receive correlated resource synchronization entries if (entryRequestType == EntryRequestType.Multi) { int pageNumber = FeedMetadataHelpers.GetPageNumber(_requestContext); correlatedResSyncInfos = correlatedResSyncStore.GetPaged(resourceKindName, pageNumber, FeedMetadataHelpers.DEFAULT_ITEMS_PER_PAGE, out totalResult); } else { Guid uuid = (Guid)TypeDescriptor.GetConverter(typeof(Guid)).ConvertFrom(_requestContext.ResourceKey); correlatedResSyncInfos = correlatedResSyncStore.GetByUuid(resourceKindName, new Guid[] { uuid }); totalResult = correlatedResSyncInfos.Length; } // Create the feed SyncFeed feed = new SyncFeed(); // initialize the feed feed.Id = FeedMetadataHelpers.BuildBaseUrl(_requestContext, FeedMetadataHelpers.RequestKeywordType.linked); feed.Title = string.Format("{0} Linking Feed", resourceKindName); #region PAGING & OPENSEARCH /* PAGING */ feed.Links = FeedMetadataHelpers.CreatePageFeedLinks(_requestContext, totalResult, FeedMetadataHelpers.RequestKeywordType.linked); /* OPENSEARCH */ PageController pageLinkBuilder = FeedMetadataHelpers.GetPageLinkBuilder(_requestContext, totalResult, FeedMetadataHelpers.RequestKeywordType.linked); feed.Opensearch_ItemsPerPageElement = pageLinkBuilder.GetOpensearch_ItemsPerPageElement(); feed.Opensearch_StartIndexElement = pageLinkBuilder.GetOpensearch_StartIndexElement(); feed.Opensearch_TotalResultsElement = pageLinkBuilder.GetOpensearch_TotalResultsElement(); #endregion feed.FeedType = (entryRequestType == EntryRequestType.Multi) ? FeedType.Linked : FeedType.LinkedSingle; IEntityWrapper wrapper = null; if (includeDataPayloads) { wrapper = EntityWrapperFactory.Create(_requestContext.ResourceKind, _requestContext); } for (int i = 0; i < correlatedResSyncInfos.Length; i++) { SyncFeedEntry entry = null; if (includeDataPayloads) { entry = wrapper.GetFeedEntry(correlatedResSyncInfos[i].LocalId); } else { entry = new SyncFeedEntry(); } entry.Id = FeedMetadataHelpers.BuildLinkedEntryUrl(_requestContext, correlatedResSyncInfos[i].ResSyncInfo.Uuid); entry.Title = FeedMetadataHelpers.BuildLinkedEntryTitle(_requestContext, correlatedResSyncInfos[i].ResSyncInfo.Uuid); #region LINKED ELEMENT LinkedElement linkedElement = new LinkedElement(); linkedElement.Resource = FeedMetadataHelpers.BuildEntryResourceUrl(_requestContext, correlatedResSyncInfos[i].LocalId); linkedElement.Uuid = correlatedResSyncInfos[i].ResSyncInfo.Uuid; entry.Linked = linkedElement; #endregion feed.Entries.Add(entry); } request.Response.Serializer = new SyncFeedSerializer(); request.Response.Feed = (IFeed)feed; request.Response.ContentType = (entryRequestType == EntryRequestType.Multi) ? MediaType.Atom : MediaType.AtomEntry; }
public void DoWork(IRequest request) { if (request.ContentType != Sage.Common.Syndication.MediaType.AtomEntry) { throw new RequestException("Atom entry content type expected"); } if (String.IsNullOrEmpty(_requestContext.ResourceKey)) { throw new RequestException("Please use single resource url"); } //SupportedResourceKinds resKind = _requestContext.ResourceKind; //switch (resKind) //{ // case SupportedResourceKinds.tradingAccounts: // case SupportedResourceKinds.contacts: // case SupportedResourceKinds.phoneNumbers: // case SupportedResourceKinds.postalAddresses: // break; // default: // throw new RequestException("Put is not Supported for requested resource"); //} // read entry from stream SyncFeedEntry entry = new SyncFeedEntry(); XmlReader reader = XmlReader.Create(request.Stream); reader.MoveToContent(); entry.ReadXml(reader, ResourceKindHelpers.GetPayloadType(_requestContext.ResourceKind)); IEntityWrapper wrapper = EntityWrapperFactory.Create(_requestContext.ResourceKind, _requestContext); Token emptyToken = new Token(); Identity identity = wrapper.GetIdentity(_requestContext.ResourceKey); Document originalDocument = wrapper.Entity.GetDocument(identity, emptyToken, _requestContext.Config); if (originalDocument.LogState == LogState.Deleted) { throw new RequestException("Entity does not exists"); } entry.Payload.LocalID = _requestContext.ResourceKey; SdataTransactionResult sdTrResult = wrapper.Update(entry.Payload, entry.SyncLinks); if (sdTrResult == null) { SyncFeedEntry responseEntry = wrapper.GetFeedEntry(_requestContext.ResourceKey); SyncFeed feed = new SyncFeed(); feed.FeedType = FeedType.ResourceEntry; feed.Entries.Add(responseEntry); request.Response.Serializer = new SyncFeedSerializer(); request.Response.Feed = feed; request.Response.ContentType = Sage.Common.Syndication.MediaType.AtomEntry; } else if (sdTrResult.HttpStatus == System.Net.HttpStatusCode.OK) { SyncFeedEntry responseEntry = wrapper.GetFeedEntry(_requestContext.ResourceKey); SyncFeed feed = new SyncFeed(); feed.FeedType = FeedType.ResourceEntry; feed.Entries.Add(responseEntry); request.Response.Serializer = new SyncFeedSerializer(); request.Response.Feed = feed; request.Response.ContentType = Sage.Common.Syndication.MediaType.AtomEntry; } else { throw new RequestException(sdTrResult.HttpMessage); } }
/// <summary> /// /// </summary> /// <param name="config"></param> /// <returns></returns> /// <remarks>This method is not threadsafe as the performer must be finished when calling this method.</remarks> public SyncFeed GetFeed(NorthwindConfig config, int startIndex, int count) { SyncFeed feed; SdataContext sdataContext; SupportedResourceKinds resource; string resourceKind; string endpoint; Guid trackingId; List <SdataTransactionResult> transactinResults; sdataContext = _parentPerformer._requestContext.SdataContext; resource = _parentPerformer._requestContext.ResourceKind; resourceKind = resource.ToString(); transactinResults = _parentPerformer._asyncStateObj.TransactionResults; endpoint = _parentPerformer._requestContext.DatasetLink + resourceKind;; trackingId = _parentPerformer._requestContext.TrackingId; if (count == 0) { count = 10; } feed = new SyncFeed(); Token emptyToken = new Token(); IEntityWrapper wrapper = EntityWrapperFactory.Create(resource, _parentPerformer._requestContext); for (int index = startIndex; index < ((startIndex + count > transactinResults.Count) ? transactinResults.Count : startIndex + count); index++) { SdataTransactionResult transactionResult = (SdataTransactionResult)transactinResults[index]; SyncFeedEntry entry = wrapper.GetFeedEntry(transactionResult); if (entry != null) { feed.Entries.Add(entry); } else { entry = new SyncFeedEntry(); entry.Uuid = transactionResult.Uuid; entry.HttpStatusCode = transactionResult.HttpStatus; entry.HttpMessage = transactionResult.HttpMessage;; entry.HttpMethod = transactionResult.HttpMethod; entry.HttpLocation = transactionResult.Location; entry.HttpETag = transactionResult.Etag; feed.Entries.Add(entry); } } // initialize the feed string url = string.Format("{0}/$syncTarget('{1}')", endpoint, trackingId); feed.Title = resourceKind; feed.Id = url; #region PAGING & OPENSEARCH int totalResults = transactinResults.Count; PageController pageController = new PageController(startIndex + 1, FeedMetadataHelpers.DEFAULT_ITEMS_PER_PAGE, totalResults, count, url); /* PAGING */ FeedLinkCollection feedLinks = new FeedLinkCollection(); feedLinks.Add(new FeedLink(pageController.GetLinkSelf(), LinkType.Self, MediaType.Atom, "Current Page")); feedLinks.Add(new FeedLink(pageController.GetLinkFirst(), LinkType.First, MediaType.Atom, "First Page")); feedLinks.Add(new FeedLink(pageController.GetLinkLast(), LinkType.Last, MediaType.Atom, "Last Page")); string linkUrl; if (pageController.GetLinkNext(out linkUrl)) { feedLinks.Add(new FeedLink(linkUrl, LinkType.Next, MediaType.Atom, "Next Page")); } if (pageController.GetLinkPrevious(out linkUrl)) { feedLinks.Add(new FeedLink(linkUrl, LinkType.Previous, MediaType.Atom, "Previous Page")); } feed.Links = feedLinks; /* OPENSEARCH */ feed.Opensearch_ItemsPerPageElement = pageController.GetOpensearch_ItemsPerPageElement(); feed.Opensearch_StartIndexElement = pageController.GetOpensearch_StartIndexElement(); feed.Opensearch_TotalResultsElement = pageController.GetOpensearch_TotalResultsElement(); #endregion //if (startIndex + count < transactinResults.Count) //{ // FeedLink linkNext = new FeedLink(string.Format("{0}?startIndex={1}&count=10", url, startIndex + count), LinkType.Next); // feed.Links.Add(linkNext); //} //FeedLink linkFirst = new FeedLink(String.Format("{0}?startIndex=0&count=10", url), LinkType.First); //feed.Links.Add(linkFirst); //FeedLink linkSelf = new FeedLink(String.Format("{0}?startIndex={1}&count=10", url, startIndex), LinkType.Self); //feed.Links.Add(linkSelf); return(feed); }
/// <summary> /// /// </summary> public void Add(TEntity entity) { EntityUtil.CheckArgumentNull(entity, "entity"); Add(EntityWrapperFactory.WrapEntityUsingContext(entity, ObjectContext)); }
// Asynchronous called method private void Execute(NorthwindConfig config, SyncFeedDigest syncDigestInfo) { #region Declaration SdataContext sdataContext; SupportedResourceKinds resource; IAppBookmarkInfoStore appBookmarkInfoStore; ICorrelatedResSyncInfoStore correlatedResSyncInfoStore; ISyncSyncDigestInfoStore syncDigestStore; ISyncTickProvider tickProvider; string resourceKind; string endpoint; int nextTick = 0; Token lastToken; Token nextToken; Identity[] changedIdentites; IEntityWrapper wrapper; #endregion #region init sdataContext = _parentPerformer._requestContext.SdataContext; resource = _parentPerformer._requestContext.ResourceKind; resourceKind = resource.ToString(); endpoint = _parentPerformer._requestContext.DatasetLink + resourceKind; appBookmarkInfoStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetAppBookmarkStore(sdataContext); correlatedResSyncInfoStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetCorrelatedResSyncStore(sdataContext); syncDigestStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetSyncDigestStore(sdataContext); tickProvider = RequestReceiver.NorthwindAdapter.StoreLocator.GetTickProvider(sdataContext); wrapper = EntityWrapperFactory.Create(resource, _parentPerformer._requestContext); #endregion #region get last token or create a new one if (!appBookmarkInfoStore.Get <Token>(resourceKind, out lastToken)) { lastToken = new Token(); lastToken.InitRequest = true; } #endregion #region Get local identities of changed entries since last synchronisation changedIdentites = wrapper.Entity.GetLastChanges(lastToken, config, out nextToken); #endregion if (resource == SupportedResourceKinds.phoneNumbers) { #region workaround for phones for (int index = 0; index < changedIdentites.Length; index++) { string phoneid = changedIdentites[index].Id + Sage.Integration.Northwind.Application.API.Constants.PhoneIdPostfix; string faxId = changedIdentites[index].Id + Sage.Integration.Northwind.Application.API.Constants.FaxIdPostfix; // receive the feed entry for local identity SyncFeedEntry phoneentry = wrapper.GetFeedEntry(phoneid); SyncFeedEntry faxentry = wrapper.GetFeedEntry(faxId); if (phoneentry == null && faxentry == null) { continue; } // receive the correlation for the local identity if (phoneentry != null) { CorrelatedResSyncInfo[] correlatedResSyncInfos = correlatedResSyncInfoStore.GetByLocalId(resourceKind, new string[] { phoneid }); string etag = EtagServices.ComputeEtag(phoneentry.Payload, true); // new etag if (correlatedResSyncInfos.Length == 0) { nextTick = tickProvider.CreateNextTick(resourceKind); // create next tick ResSyncInfo resyncInfo = new ResSyncInfo(Guid.NewGuid(), endpoint, nextTick, etag, DateTime.Now); CorrelatedResSyncInfo info = new CorrelatedResSyncInfo(phoneid, resyncInfo); correlatedResSyncInfoStore.Put(resourceKind, info); syncDigestStore.PersistNewer(resourceKind, info.ResSyncInfo); } else if (!correlatedResSyncInfos[0].ResSyncInfo.Etag.Equals(etag)) { nextTick = tickProvider.CreateNextTick(resourceKind); correlatedResSyncInfos[0].ResSyncInfo.Etag = etag; correlatedResSyncInfos[0].ResSyncInfo.Tick = nextTick; correlatedResSyncInfos[0].ResSyncInfo.Endpoint = endpoint; correlatedResSyncInfos[0].ResSyncInfo.ModifiedStamp = DateTime.Now; correlatedResSyncInfoStore.Put(resourceKind, correlatedResSyncInfos[0]); syncDigestStore.PersistNewer(resourceKind, correlatedResSyncInfos[0].ResSyncInfo); } } if (faxentry != null) { CorrelatedResSyncInfo[] correlatedResSyncInfos = correlatedResSyncInfoStore.GetByLocalId(resourceKind, new string[] { faxId }); string etag = EtagServices.ComputeEtag(faxentry.Payload, true); // new etag if (correlatedResSyncInfos.Length == 0) { nextTick = tickProvider.CreateNextTick(resourceKind); // create next tick ResSyncInfo resyncInfo = new ResSyncInfo(Guid.NewGuid(), endpoint, nextTick, etag, DateTime.Now); CorrelatedResSyncInfo info = new CorrelatedResSyncInfo(faxId, resyncInfo); correlatedResSyncInfoStore.Put(resourceKind, info); syncDigestStore.PersistNewer(resourceKind, info.ResSyncInfo); } else if (!correlatedResSyncInfos[0].ResSyncInfo.Etag.Equals(etag)) { nextTick = tickProvider.CreateNextTick(resourceKind); correlatedResSyncInfos[0].ResSyncInfo.Etag = etag; correlatedResSyncInfos[0].ResSyncInfo.Tick = nextTick; correlatedResSyncInfos[0].ResSyncInfo.Endpoint = endpoint; correlatedResSyncInfos[0].ResSyncInfo.ModifiedStamp = DateTime.Now; correlatedResSyncInfoStore.Put(resourceKind, correlatedResSyncInfos[0]); syncDigestStore.PersistNewer(resourceKind, correlatedResSyncInfos[0].ResSyncInfo); } } } #endregion } else { for (int index = 0; index < changedIdentites.Length; index++) { string id = changedIdentites[index].Id; // receive the feed entry for local identity SyncFeedEntry entry = wrapper.GetFeedEntry(id); if (entry == null) { continue; } // receive the correlation for the local identity CorrelatedResSyncInfo[] correlatedResSyncInfos = correlatedResSyncInfoStore.GetByLocalId(resourceKind, new string[] { id }); string etag = EtagServices.ComputeEtag(entry.Payload, true); // new etag if (correlatedResSyncInfos.Length == 0) { nextTick = tickProvider.CreateNextTick(resourceKind); // create next tick ResSyncInfo resyncInfo = new ResSyncInfo(Guid.NewGuid(), endpoint, nextTick, etag, DateTime.Now); CorrelatedResSyncInfo info = new CorrelatedResSyncInfo(id, resyncInfo); correlatedResSyncInfoStore.Put(resourceKind, info); syncDigestStore.PersistNewer(resourceKind, info.ResSyncInfo); } else if (!correlatedResSyncInfos[0].ResSyncInfo.Etag.Equals(etag)) { nextTick = tickProvider.CreateNextTick(resourceKind); correlatedResSyncInfos[0].ResSyncInfo.Etag = etag; correlatedResSyncInfos[0].ResSyncInfo.Tick = nextTick; correlatedResSyncInfos[0].ResSyncInfo.Endpoint = endpoint; correlatedResSyncInfos[0].ResSyncInfo.ModifiedStamp = DateTime.Now; correlatedResSyncInfoStore.Put(resourceKind, correlatedResSyncInfos[0]); syncDigestStore.PersistNewer(resourceKind, correlatedResSyncInfos[0].ResSyncInfo); } } } #region store next token appBookmarkInfoStore.Put(resourceKind, nextToken); #endregion // set tracking phase lock (_parentPerformer._asyncStateObj) { _parentPerformer._asyncStateObj.Tracking.Phase = TrackingPhase.GETCHANGESBYTICK; } // Receive syncDigestInfo if (null != syncDigestInfo) { ICorrelatedResSyncInfoEnumerator enumerator; List <string> endpoints = new List <string>(); foreach (SyncFeedDigestEntry digestEntry in syncDigestInfo.Entries) { endpoints.Add(digestEntry.Endpoint); enumerator = correlatedResSyncInfoStore.GetSinceTick(resourceKind, digestEntry.Endpoint, digestEntry.Tick - 2); while (enumerator.MoveNext()) { // No lock needed, as we expect that CorrelatedResSyncInfos list is // only acceeded anywhere else when Tracking phase is 'finish'. //lock(_parentPerformer._asyncStateObj) //{ _parentPerformer._asyncStateObj.CorrelatedResSyncInfos.Add(enumerator.Current); //} } } SyncDigestInfo sourceSyncDigestInfo = syncDigestStore.Get(resourceKind); foreach (SyncDigestEntryInfo digestEntry in sourceSyncDigestInfo) { if (endpoints.Contains(digestEntry.Endpoint)) { continue; } endpoints.Add(digestEntry.Endpoint); enumerator = correlatedResSyncInfoStore.GetSinceTick(resourceKind, digestEntry.Endpoint, -1); while (enumerator.MoveNext()) { // No lock needed, as we expect that CorrelatedResSyncInfos list is // only acceeded anywhere else when Tracking phase is 'finish'. //lock(_parentPerformer._asyncStateObj) //{ _parentPerformer._asyncStateObj.CorrelatedResSyncInfos.Add(enumerator.Current); //} } } if (!endpoints.Contains(endpoint)) { enumerator = correlatedResSyncInfoStore.GetSinceTick(resourceKind, endpoint, -1); while (enumerator.MoveNext()) { // No lock needed, as we expect that CorrelatedResSyncInfos list is // only acceeded anywhere else when Tracking phase is 'finish'. //lock(_parentPerformer._asyncStateObj) //{ _parentPerformer._asyncStateObj.CorrelatedResSyncInfos.Add(enumerator.Current); //} } } } // Set tracking phase lock (_parentPerformer._asyncStateObj.Tracking) { _parentPerformer._asyncStateObj.Tracking.Phase = TrackingPhase.FINISH; } }
/// <summary> /// /// </summary> /// <param name="config"></param> /// <returns></returns> /// <remarks>This method is not threadsafe as the performer must be finished when calling this method.</remarks> public SyncFeed GetFeed(NorthwindConfig config, int startIndex, int count) { SyncFeed feed; SdataContext sdataContext; SupportedResourceKinds resource; string resourceKind; string endpoint; Guid trackingId; List <CorrelatedResSyncInfo> correlatedResSyncInfos; sdataContext = _parentPerformer._requestContext.SdataContext; resource = _parentPerformer._requestContext.ResourceKind; resourceKind = resource.ToString(); correlatedResSyncInfos = _parentPerformer._asyncStateObj.CorrelatedResSyncInfos; endpoint = _parentPerformer._requestContext.DatasetLink + resourceKind; trackingId = _parentPerformer._requestContext.TrackingId; ISyncSyncDigestInfoStore syncDigestStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetSyncDigestStore(sdataContext); SyncDigestInfo syncDigestInfo = syncDigestStore.Get(resourceKind); if (count == 0) { count = 10; } feed = new SyncFeed(); Token emptyToken = new Token(); feed.Digest = new SyncFeedDigest(); feed.Digest.Origin = _parentPerformer._requestContext.OriginEndPoint; feed.Digest.Entries = new List <SyncFeedDigestEntry>(); if (syncDigestInfo != null) { foreach (SyncDigestEntryInfo entryinfo in syncDigestInfo) { SyncFeedDigestEntry entry = new SyncFeedDigestEntry(); entry.ConflictPriority = entryinfo.ConflictPriority; entry.Endpoint = entryinfo.Endpoint; entry.Tick = entryinfo.Tick; entry.Stamp = DateTime.Now; feed.Digest.Entries.Add(entry); } } IEntityWrapper wrapper = EntityWrapperFactory.Create(resource, _parentPerformer._requestContext); for (int index = startIndex; index < ((startIndex + count > correlatedResSyncInfos.Count) ? correlatedResSyncInfos.Count : startIndex + count); index++) { CorrelatedResSyncInfo resSyncInfo = (CorrelatedResSyncInfo)correlatedResSyncInfos[index]; SyncFeedEntry entry = wrapper.GetFeedEntry(resSyncInfo); if (entry != null) { feed.Entries.Add(entry); } else { entry = new SyncFeedEntry(); entry.HttpMethod = "DELETE"; entry.Uuid = resSyncInfo.ResSyncInfo.Uuid; feed.Entries.Add(entry); } } // initialize the feed string url = string.Format("{0}/$syncSource('{1}')", endpoint, trackingId); feed.Id = url; feed.Title = resourceKind; #region PAGING & OPENSEARCH int totalResults = correlatedResSyncInfos.Count; PageController pageController = new PageController(startIndex + 1, FeedMetadataHelpers.DEFAULT_ITEMS_PER_PAGE, totalResults, count, url); /* PAGING */ FeedLinkCollection feedLinks = new FeedLinkCollection(); feedLinks.Add(new FeedLink(pageController.GetLinkSelf(), LinkType.Self, MediaType.Atom, "Current Page")); feedLinks.Add(new FeedLink(pageController.GetLinkFirst(), LinkType.First, MediaType.Atom, "First Page")); feedLinks.Add(new FeedLink(pageController.GetLinkLast(), LinkType.Last, MediaType.Atom, "Last Page")); string linkUrl; if (pageController.GetLinkNext(out linkUrl)) { feedLinks.Add(new FeedLink(linkUrl, LinkType.Next, MediaType.Atom, "Next Page")); } if (pageController.GetLinkPrevious(out linkUrl)) { feedLinks.Add(new FeedLink(linkUrl, LinkType.Previous, MediaType.Atom, "Previous Page")); } feed.Links = feedLinks; /* OPENSEARCH */ feed.Opensearch_ItemsPerPageElement = pageController.GetOpensearch_ItemsPerPageElement(); feed.Opensearch_StartIndexElement = pageController.GetOpensearch_StartIndexElement(); feed.Opensearch_TotalResultsElement = pageController.GetOpensearch_TotalResultsElement(); #endregion //feed.Id = url; //if (startIndex + count < correlatedResSyncInfos.Count) //{ // FeedLink linkNext = new FeedLink(string.Format("{0}?startIndex={1}&count=10", url, startIndex + count), LinkType.Next); // feed.Links.Add(linkNext); //} //FeedLink linkFirst = new FeedLink(String.Format("{0}?startIndex=0&count=10", url), LinkType.First); //feed.Links.Add(linkFirst); //FeedLink linkSelf = new FeedLink(String.Format("{0}?startIndex={1}&count=10", url, startIndex), LinkType.Self); //feed.Links.Add(linkSelf); return(feed); }