internal override OrganizationResponse Execute(OrganizationRequest orgRequest, EntityReference userRef) { var request = MakeRequest <MergeRequest>(orgRequest); var mainEntity = db.GetEntity(request.Target); var casSelection = new CascadeSelection() { merge = true }; var subordinateReference = new EntityReference { LogicalName = mainEntity.LogicalName, Id = request.SubordinateId }; var subordinateEntity = core.GetDbEntityWithRelatedEntities(subordinateReference, EntityRole.Referencing, userRef, casSelection); foreach (var attr in request.UpdateContent.Attributes) { if (attr.Value != null) { mainEntity[attr.Key] = attr.Value; } } foreach (var relatedEntities in subordinateEntity.RelatedEntities) { var relationshipMeta = metadata.EntityMetadata.GetMetadata(subordinateEntity.LogicalName).ManyToOneRelationships.First(r => r.SchemaName == relatedEntities.Key.SchemaName); if (relationshipMeta.CascadeConfiguration.Merge == CascadeType.Cascade) { var entitiesToSwap = relatedEntities.Value.Entities.Select(e => e.ToEntityReference()).ToList(); var disassocHandler = core.RequestHandlers.Find(x => x is DisassociateRequestHandler); disassocHandler.Execute(new DisassociateRequest { RelatedEntities = new EntityReferenceCollection(entitiesToSwap), Relationship = relatedEntities.Key, Target = subordinateEntity.ToEntityReference() }, userRef); var assocHandler = core.RequestHandlers.Find(x => x is AssociateRequestHandler); assocHandler.Execute(new AssociateRequest { RelatedEntities = new EntityReferenceCollection(entitiesToSwap), Relationship = relatedEntities.Key, Target = mainEntity.ToEntityReference() }, userRef); } } subordinateEntity["merged"] = true; db.Update(subordinateEntity); db.Update(mainEntity); var setStateHandler = core.RequestHandlers.Find(x => x is SetStateRequestHandler); var req = new SetStateRequest() { EntityMoniker = subordinateReference, State = new OptionSetValue(1), Status = new OptionSetValue(2) }; setStateHandler.Execute(req, userRef); return(new MergeResponse()); }
internal override OrganizationResponse Execute(OrganizationRequest orgRequest, EntityReference userRef) { var request = MakeRequest <AssignRequest>(orgRequest); var casSelection = new CascadeSelection() { assign = true }; var dbEntity = core.GetDbEntityWithRelatedEntities(request.Target, EntityRole.Referenced, userRef, casSelection); security.CheckAssignPermission(dbEntity, request.Assignee, userRef); // Cascade foreach (var relatedEntities in dbEntity.RelatedEntities) { var relationshipMeta = metadata.EntityMetadata.GetMetadata(dbEntity.LogicalName).OneToManyRelationships.First(r => r.SchemaName == relatedEntities.Key.SchemaName); var req = new AssignRequest(); switch (relationshipMeta.CascadeConfiguration.Assign) { case CascadeType.Cascade: foreach (var relatedEntity in relatedEntities.Value.Entities) { req.Target = relatedEntity.ToEntityReference(); req.Assignee = request.Assignee; core.Execute(req, userRef, null); } break; case CascadeType.Active: foreach (var relatedEntity in relatedEntities.Value.Entities) { if (db.GetEntity(relatedEntity.ToEntityReference()).GetAttributeValue <OptionSetValue>("statecode")?.Value == 0) { req.Target = relatedEntity.ToEntityReference(); req.Assignee = request.Assignee; core.Execute(req, userRef, null); } } break; case CascadeType.UserOwned: foreach (var relatedEntity in relatedEntities.Value.Entities) { var currentOwner = dbEntity.Attributes["ownerid"] as EntityReference; if (db.GetEntity(relatedEntity.ToEntityReference()).GetAttributeValue <EntityReference>("ownerid")?.Id == currentOwner.Id) { req.Target = relatedEntity.ToEntityReference(); req.Assignee = request.Assignee; core.Execute(req, userRef, null); } } break; } } Utility.SetOwner(db, security, metadata, dbEntity, request.Assignee); Utility.Touch(dbEntity, metadata.EntityMetadata.GetMetadata(dbEntity.LogicalName), core.TimeOffset, userRef); db.Update(dbEntity); return(new AssignResponse()); }
internal override OrganizationResponse Execute(OrganizationRequest orgRequest, EntityReference userRef) { var request = MakeRequest <DeleteRequest>(orgRequest); var casSelection = new CascadeSelection() { delete = true }; var entity = core.GetDbEntityWithRelatedEntities(request.Target, EntityRole.Referenced, userRef, casSelection); if (entity == null) { throw new FaultException($"{request.Target.LogicalName} with Id '{request.Target.Id}' does not exist"); } if (entity != null) { foreach (var relatedEntities in entity.RelatedEntities) { var relationshipMeta = metadata.EntityMetadata.GetMetadata(entity.LogicalName).OneToManyRelationships.FirstOrDefault(r => r.SchemaName == relatedEntities.Key.SchemaName); if (relationshipMeta == null) { continue; } switch (relationshipMeta.CascadeConfiguration.Delete) { case CascadeType.Cascade: foreach (var relatedEntity in relatedEntities.Value.Entities) { var req = new DeleteRequest { Target = new EntityReference(relatedEntity.LogicalName, relatedEntity.Id) }; core.Execute(req, userRef, null); } break; case CascadeType.RemoveLink: var disassocHandler = core.RequestHandlers.Find(x => x is DisassociateRequestHandler); disassocHandler.Execute(new DisassociateRequest { RelatedEntities = new EntityReferenceCollection(relatedEntities.Value.Entities.Select(e => e.ToEntityReference()).ToList()), Relationship = relatedEntities.Key, Target = entity.ToEntityReference() }, userRef); break; case CascadeType.Restrict: var trace = core.ServiceFactory.GetService(typeof(ITracingService)) as ITracingService; trace.Trace($"Delete restricted for {relatedEntities.Key.SchemaName} when trying to delete {entity.LogicalName} with id {entity.Id}"); return(new DeleteResponse()); } } db.Delete(entity); } return(new DeleteResponse()); }
private bool CascadeCompare(CascadeConfiguration cascadeConfiguration, CascadeSelection selection) { if (selection == null) { return(true); } if (selection.assign && HasCascadeBehaviour(cascadeConfiguration.Assign)) { return(true); } if (selection.delete && HasCascadeBehaviour(cascadeConfiguration.Delete)) { return(true); } if (selection.merge && HasCascadeBehaviour(cascadeConfiguration.Merge)) { return(true); } if (selection.reparent && HasCascadeBehaviour(cascadeConfiguration.Reparent)) { return(true); } if (selection.share && HasCascadeBehaviour(cascadeConfiguration.Share)) { return(true); } if (selection.unshare && HasCascadeBehaviour(cascadeConfiguration.Unshare)) { return(true); } #if !(XRM_MOCKUP_2011 || XRM_MOCKUP_2013 || XRM_MOCKUP_2015 || XRM_MOCKUP_2016) if (selection.rollup && HasCascadeBehaviour(cascadeConfiguration.RollupView)) { return(true); } #endif return(false); }
internal override void CheckSecurity(OrganizationRequest orgRequest, EntityReference userRef) { var request = MakeRequest <DeleteRequest>(orgRequest); var casSelection = new CascadeSelection() { delete = true }; var entity = core.GetDbEntityWithRelatedEntities(request.Target, EntityRole.Referenced, userRef, casSelection); if (entity == null) { throw new FaultException($"{request.Target.LogicalName} with Id '{request.Target.Id}' does not exist"); } if (!security.HasPermission(entity, AccessRights.DeleteAccess, userRef)) { throw new FaultException($"You do not have permission to access entity '{request.Target.LogicalName}' for delete"); } }
//TODO: update to also take in cascading filtering on Assign, Delete, Merge, reparent, rollup internal Entity GetDbEntityWithRelatedEntities(EntityReference reference, EntityRole primaryEntityRole, EntityReference userRef, CascadeSelection cascadeSelection = null, params Relationship[] relations) { var entity = db.GetEntityOrNull(reference); if (entity == null) { return(null); } var metadata = this.metadata.EntityMetadata.GetMetadata(entity.LogicalName); if (entity.RelatedEntities.Count() > 0) { var clone = entity.CloneEntity(metadata, new ColumnSet(true)); db.Update(clone); entity = clone; } var relationQuery = new RelationshipQueryCollection(); var relationsMetadata = primaryEntityRole == EntityRole.Referenced ? metadata.OneToManyRelationships : metadata.ManyToOneRelationships; if (cascadeSelection != null) { relationsMetadata.Where(x => CascadeCompare(x.CascadeConfiguration, cascadeSelection)); } if (relations.Any()) { relationsMetadata = relationsMetadata.Join(relations, x => x.SchemaName, y => y.SchemaName, (r1, r2) => r1).ToArray(); } relationQuery.AddRange( relationsMetadata .Select(relationshipMeta => { var rel = new Relationship() { SchemaName = relationshipMeta.SchemaName, PrimaryEntityRole = primaryEntityRole }; var query = new QueryExpression() { EntityName = primaryEntityRole == EntityRole.Referenced ? relationshipMeta.ReferencingEntity : relationshipMeta.ReferencedEntity, ColumnSet = new ColumnSet(true) }; return(new KeyValuePair <Relationship, QueryBase>(rel, query)); })); foreach (var relationshipMeta in relationsMetadata) { } if (cascadeSelection == null) { var relationShipManyMetadata = metadata.ManyToManyRelationships; if (relations.Any()) { relationShipManyMetadata = relationShipManyMetadata.Join(relations, x => x.SchemaName, y => y.SchemaName, (r1, r2) => r1).ToArray(); } relationQuery.AddRange(relationShipManyMetadata .Select(relationshipMeta => { var rel = new Relationship() { SchemaName = relationshipMeta.SchemaName }; var query = new QueryExpression(relationshipMeta.IntersectEntityName) { ColumnSet = new ColumnSet(true) }; return(new KeyValuePair <Relationship, QueryBase>(rel, query)); })); } AddRelatedEntities(entity, relationQuery, userRef); return(entity); }