private AttributeTypeCode?GetAttributeType(IExecutionContainer container, string attribute, string entityName) { container.StartSection(MethodBase.GetCurrentMethod().Name + " " + entityName + "." + attribute); AttributeTypeCode?type = null; var eqe = new EntityQueryExpression { Properties = new MetadataPropertiesExpression() }; eqe.Properties.PropertyNames.Add("Attributes"); eqe.Criteria.Conditions.Add(new MetadataConditionExpression("LogicalName", MetadataConditionOperator.Equals, entityName)); var aqe = new AttributeQueryExpression { Properties = new MetadataPropertiesExpression("LogicalName", "AttributeType") }; eqe.AttributeQuery = aqe; var req = new RetrieveMetadataChangesRequest() { Query = eqe, ClientVersionStamp = null }; var resp = (RetrieveMetadataChangesResponse)container.Execute(req); if (resp.EntityMetadata.Count == 1) { foreach (var attr in resp.EntityMetadata[0].Attributes) { if (attr.LogicalName == attribute) { type = attr.AttributeType; break; } } } container.Log($"Type: {type}"); container.EndSection(); return(type); }
private static bool EntityAttributesEqual(IExecutionContainer container, List <string> matchattributes, Entity entity1, Entity entity2) { var match = true; foreach (var attr in matchattributes) { var srcvalue = ""; if (attr == container.Entity(entity1.LogicalName).PrimaryIdAttribute) { srcvalue = entity1.Id.ToString(); } else { srcvalue = container.AttributeAsBaseType(entity1, attr, "<null>", true).ToString(); } var trgvalue = container.AttributeAsBaseType(entity2, attr, "<null>", true).ToString(); if (srcvalue != trgvalue) { match = false; break; } } return(match); }
private void SetNewSolutionVersion(IExecutionContainer container, string setversion, Entity cdSolution, Version currentversion) { Version newversion; if (setversion.Equals("IncrementAll", StringComparison.OrdinalIgnoreCase)) { newversion = new Version("1.0.0.0"); foreach (var existingversion in ExistingSolutionVersions.Values) { if (existingversion > newversion) { newversion = existingversion; } } newversion = IncrementVersion(newversion); } else if (setversion.Equals("Increment", StringComparison.OrdinalIgnoreCase)) { newversion = IncrementVersion(currentversion); } else if (setversion.Equals("Current", StringComparison.OrdinalIgnoreCase)) { newversion = currentversion; } else { newversion = new Version(setversion); } if (!currentversion.Equals(newversion)) { SendLine(container, $"Setting version: {newversion}"); var cdSolUpd = cdSolution.CloneId(); cdSolUpd.SetAttribute("version", newversion.ToString()); container.Save(cdSolUpd); } }
/// <summary> /// Initiates work with principals which is followed with access related opetations: Grant / Revoke / Assign /// </summary> /// <param name="container"></param> /// <param name="principal"></param> /// <returns></returns> public static Fluent.Access.OperationsSet1 Principal(this IExecutionContainer container, Entity principal) => container.Principal(principal.ToEntityReference());
/// <summary> /// Initiates work with entitites /// </summary> /// <param name="container"></param> /// <param name="target"></param> /// <returns></returns> public static Fluent.Entity.OperationsSet1 Entity(this IExecutionContainer container, EntityReference target) => new Fluent.Entity.OperationsSet1(container, new Entity(target.LogicalName, target.Id));
/// <summary> /// Initiates work with attributes /// </summary> /// <param name="container"></param> /// <param name="name"></param> /// <returns></returns> public static Fluent.Attribute.OperationsSet1 Attribute(this IExecutionContainer container, string name) => new Fluent.Attribute.OperationsSet1(container, name);
/// <summary>Reloads encapsulated Entity from database</summary> /// <param name="container"></param> /// <param name="entity"></param> /// <param name="columns">Set of colums with which entity should be reloaded</param> /// <remarks>ToStringWithEntityName() is replaced with entity.LogicalName</remarks> public static Entity Reload(this IExecutionContainer container, Entity entity, params string[] columns) => container.Reload(entity, new ColumnSet(columns));
/// <summary> /// Checks if a property exists in the encapsulated Entity /// </summary> /// <param name="container"></param> /// <param name="entity"></param> /// <param name="attribute">Name of property to check</param> /// <returns></returns> public static Entity Ensure(this IExecutionContainer container, Entity entity, string attribute) => entity.Contains(attribute) ? entity : container.Reload(entity, attribute);
internal OperationsSet1(IExecutionContainer container, EntityReference principal) : base(container, principal) { }
internal Information(IExecutionContainer container, EntityReference principal) : base(container) => this.principal = principal;
public static void PublishDuplicateRule(this IExecutionContainer container, Entity duplicateRule) => container.Execute(new PublishDuplicateRuleRequest { DuplicateRuleId = duplicateRule.Id });
private bool SaveEntity(IExecutionContainer container, Entity cdNewEntity, Entity cdMatchEntity, bool updateInactiveRecord, bool updateIdentical, int pos, string identifier) { container.StartSection("SaveEntity " + pos.ToString("000 ") + identifier); var recordSaved = false; if (string.IsNullOrWhiteSpace(identifier)) { identifier = cdNewEntity.ToString(); } var newOwner = cdNewEntity.GetAttribute <EntityReference>("ownerid", null); var newState = cdNewEntity.GetAttribute <OptionSetValue>("statecode", null); var newStatus = cdNewEntity.GetAttribute <OptionSetValue>("statuscode", null); var newActive = newState != null?container.GetActiveStates(cdNewEntity.LogicalName).Contains(newState.Value) : true; var nowActive = true; if ((newState == null) != (newStatus == null)) { throw new InvalidDataException("When setting status of the record, both statecode and statuscode must be present"); } if (!newActive) { container.Log("Removing state+status from entity to update"); cdNewEntity.RemoveAttribute("statecode"); cdNewEntity.RemoveAttribute("statuscode"); } if (cdMatchEntity == null) { container.Create(cdNewEntity); recordSaved = true; SendLine(container, "{0:000} Created: {1}", pos, identifier); } else { var oldState = cdMatchEntity.GetAttribute <OptionSetValue>("statecode", null); var oldActive = oldState != null?container.GetActiveStates(cdNewEntity.LogicalName).Contains(oldState.Value) : true; nowActive = oldActive; cdNewEntity.Id = cdMatchEntity.Id; if (!oldActive && (newActive || updateInactiveRecord)) { // Inaktiv post som ska aktiveras eller uppdateras container.SetState(cdNewEntity, 0, 1); SendLine(container, "{0:000} Activated: {1} for update", pos, identifier); nowActive = true; } if (nowActive) { var updateattributes = cdNewEntity.Attributes.Keys.ToList(); if (updateattributes.Contains(container.Entity(cdNewEntity.LogicalName).PrimaryIdAttribute)) { updateattributes.Remove(container.Entity(cdNewEntity.LogicalName).PrimaryIdAttribute); } if (updateIdentical || !EntityAttributesEqual(container, updateattributes, cdNewEntity, cdMatchEntity)) { try { container.Update(cdNewEntity); recordSaved = true; SendLine(container, "{0:000} Updated: {1}", pos, identifier); } catch (Exception) { recordSaved = false; SendLine(container, "{0:000} Update Failed: {1} {2} {3}", pos, identifier, cdNewEntity.LogicalName); } } else { SendLine(container, "{0:000} Skipped: {1} (Identical)", pos, identifier); } } else { SendLine(container, "{0:000} Inactive: {1}", pos, identifier); } if (newOwner != null && !newOwner.Equals(cdMatchEntity.GetAttribute("ownerid", new EntityReference()))) { container.Principal(cdNewEntity).On(newOwner).Assign(); // cdNewEntity.Assign(newOwner); SendLine(container, "{0:000} Assigned: {1} to {2} {3}", pos, identifier, newOwner.LogicalName, string.IsNullOrEmpty(newOwner.Name) ? newOwner.Id.ToString() : newOwner.Name); } } if (newActive != nowActive) { // Active should be changed on the record var newStatusValue = newStatus.Value; if (cdNewEntity.LogicalName == "savedquery" && newState.Value == 1 && newStatusValue == 1) { // Adjustment for inactive but unpublished view newStatusValue = 2; } if (cdNewEntity.LogicalName == "duplicaterule") { if (newStatusValue == 2) { container.PublishDuplicateRule(cdNewEntity); SendLine(container, "{0:000} Publish Duplicate Rule: {1}", pos, identifier); } else { container.UnpublishDuplicateRule(cdNewEntity); SendLine(container, "{0:000} Unpublish Duplicate Rule: {1}", pos, identifier); } } else { container.SetState(cdNewEntity, newState.Value, newStatusValue); SendLine(container, "{0:000} SetState: {1}: {2}/{3}", pos, identifier, newState.Value, newStatus.Value); } } container.EndSection(); return(recordSaved); }
private Tuple <int, int, int, int, int, EntityReferenceCollection> ImportDataBlock(IExecutionContainer container, DataBlock block, EntityCollection cEntities) { container.StartSection("ImportDataBlock"); var created = 0; var updated = 0; var skipped = 0; var deleted = 0; var failed = 0; var references = new EntityReferenceCollection(); var name = block.Name; container.Log($"Block: {name}"); SendStatus(name, null); SendLine(container); if (block.Import != null) { var includeid = block.Import.CreateWithId; var save = block.Import.Save; var delete = block.Import.Delete; var updateinactive = block.Import.UpdateInactive; var updateidentical = block.Import.UpdateIdentical; if (block.Import.OverwriteSpecified) { SendLine(container, "DEPRECATED use of attribute Overwrite!"); save = block.Import.Overwrite ? SaveTypes.CreateUpdate : SaveTypes.CreateOnly; } var matchattributes = GetMatchAttributes(block.Import.Match); var updateattributes = !updateidentical?GetUpdateAttributes(cEntities) : new List <string>(); var preretrieveall = block.Import.Match?.PreRetrieveAll == true; SendLine(container); SendLine(container, $"Importing block {name} - {cEntities.Count()} records "); var i = 1; if (delete == DeleteTypes.All && (matchattributes.Count == 0)) { // All records shall be deleted, no match attribute defined, so just get all and delete all var entity = block.Entity; var qDelete = new QueryExpression(entity); qDelete.ColumnSet.AddColumn(container.Entity(entity).PrimaryNameAttribute); var deleterecords = container.RetrieveMultiple(qDelete); //var deleterecords = Entity.RetrieveMultiple(crmsvc, qDelete, log); SendLine(container, $"Deleting ALL {entity} - {deleterecords.Count()} records"); foreach (var record in deleterecords.Entities) { SendLine(container, "{0:000} Deleting existing: {1}", i, record); try { container.Delete(record); deleted++; } catch (FaultException <OrganizationServiceFault> ex) { if (ex.Message.ToUpperInvariant().Contains("DOES NOT EXIST")) { // This may happen through delayed cascade delete in CRM SendLine(container, " ...already deleted"); } else { throw; } } i++; } } var totalRecords = cEntities.Count(); i = 1; EntityCollection cAllRecordsToMatch = null; foreach (var cdEntity in cEntities.Entities) { var unique = cdEntity.Id.ToString(); SendStatus(-1, -1, totalRecords, i); try { var oldid = cdEntity.Id; var newid = Guid.Empty; ReplaceGuids(container, cdEntity, includeid); ReplaceUpdateInfo(cdEntity); unique = GetEntityDisplayString(container, block.Import.Match, cdEntity); SendStatus(null, unique); if (!block.TypeSpecified || block.Type == EntityTypes.Entity) { #region Entity if (matchattributes.Count == 0) { if (save == SaveTypes.Never || save == SaveTypes.UpdateOnly) { skipped++; SendLine(container, "{0:000} Not saving: {1}", i, unique); } else { if (!includeid) { cdEntity.Id = Guid.Empty; } if (SaveEntity(container, cdEntity, null, updateinactive, updateidentical, i, unique)) { created++; newid = cdEntity.Id; references.Add(cdEntity.ToEntityReference()); } } } else { var matches = GetMatchingRecords(container, cdEntity, matchattributes, updateattributes, preretrieveall, ref cAllRecordsToMatch); if (delete == DeleteTypes.All || (matches.Count() == 1 && delete == DeleteTypes.Existing)) { foreach (var cdMatch in matches.Entities) { SendLine(container, "{0:000} Deleting existing: {1}", i, unique); try { container.Delete(cdMatch); deleted++; } catch (FaultException <OrganizationServiceFault> ex) { if (ex.Message.ToUpperInvariant().Contains("DOES NOT EXIST")) { // This may happen through cascade delete in CRM SendLine(container, " ...already deleted"); } else { throw; } } } matches.Entities.Clear(); } if (matches.Count() == 0) { if (save == SaveTypes.Never || save == SaveTypes.UpdateOnly) { skipped++; SendLine(container, "{0:000} Not creating: {1}", i, unique); } else { if (!includeid) { cdEntity.Id = Guid.Empty; } if (SaveEntity(container, cdEntity, null, updateinactive, updateidentical, i, unique)) { created++; newid = cdEntity.Id; references.Add(cdEntity.ToEntityReference()); } } } else if (matches.Count() == 1) { var match = matches[0]; newid = match.Id; if (save == SaveTypes.CreateUpdate || save == SaveTypes.UpdateOnly) { if (SaveEntity(container, cdEntity, match, updateinactive, updateidentical, i, unique)) { updated++; references.Add(cdEntity.ToEntityReference()); } else { skipped++; } } else { skipped++; SendLine(container, "{0:000} Exists: {1}", i, unique); } } else { failed++; SendLine(container, $"Import object matches {matches.Count()} records in target database!"); SendLine(container, unique); } } if (!oldid.Equals(Guid.Empty) && !newid.Equals(Guid.Empty) && !oldid.Equals(newid) && !guidmap.ContainsKey(oldid)) { container.Log("Mapping IDs: {0} ==> {1}", oldid, newid); guidmap.Add(oldid, newid); } #endregion Entity } else if (block.Type == EntityTypes.Intersect) { #region Intersect if (cdEntity.Attributes.Count != 2) { throw new ArgumentOutOfRangeException("Attributes", cdEntity.Attributes.Count, "Invalid Attribute count for intersect object"); } var intersect = block.IntersectName; if (string.IsNullOrEmpty(intersect)) { intersect = cdEntity.LogicalName; } var ref1 = (EntityReference)cdEntity.Attributes.ElementAt(0).Value; var ref2 = (EntityReference)cdEntity.Attributes.ElementAt(1).Value; var party1 = new Entity(ref1.LogicalName, ref1.Id); //Entity.InitFromNameAndId(ref1.LogicalName, ref1.Id, crmsvc, log); var party2 = new Entity(ref2.LogicalName, ref2.Id); //Entity.InitFromNameAndId(ref2.LogicalName, ref2.Id, crmsvc, log); try { container.Associate(party1, party2, intersect); //party1.Associate(party2, intersect); created++; SendLine(container, "{0} Associated: {1}", i.ToString().PadLeft(3, '0'), name); } catch (Exception ex) { if (ex.Message.Contains("duplicate")) { SendLine(container, "{0} Association exists: {1}", i.ToString().PadLeft(3, '0'), name); skipped++; } else { throw; } } #endregion Intersect } } catch (Exception ex) { failed++; SendLine(container, $"\n*** Error record: {unique} ***\n{ex.Message}"); container.Log(ex); if (stoponerror) { throw; } } i++; } SendLine(container, $"Created: {created} Updated: {updated} Skipped: {skipped} Deleted: {deleted} Failed: {failed}"); } container.EndSection(); return(new Tuple <int, int, int, int, int, EntityReferenceCollection>(created, updated, skipped, deleted, failed, references)); }
private EntityCollection GetMatchingRecords(IExecutionContainer container, Entity cdEntity, List <string> matchattributes, List <string> updateattributes, bool preretrieveall, ref EntityCollection cAllRecordsToMatch) { container.StartSection(MethodBase.GetCurrentMethod().Name); EntityCollection matches = null; var allattributes = new List <string> { container.Entity(cdEntity.LogicalName).PrimaryIdAttribute }; if (cdEntity.Contains("ownerid")) { allattributes.Add("ownerid"); } if (cdEntity.Contains("statecode") || cdEntity.Contains("statuscode")) { allattributes.Add("statecode"); allattributes.Add("statuscode"); } allattributes = allattributes.Union(matchattributes.Union(updateattributes)).ToList(); if (preretrieveall) { if (cAllRecordsToMatch == null) { cAllRecordsToMatch = GetAllRecordsForMatching(container, allattributes, cdEntity); } matches = GetMatchingRecordsFromPreRetrieved(container, matchattributes, cdEntity, cAllRecordsToMatch); } else { var qMatch = new QueryExpression(cdEntity.LogicalName) { // We need to be able to see if any attributes have changed, so lets make sure matching records have all the attributes that will be updated ColumnSet = new ColumnSet(allattributes.ToArray()) }; foreach (var matchattr in matchattributes) { object value = null; if (cdEntity.Contains(matchattr)) { value = container.AttributeAsBaseType(cdEntity, matchattr, null, false); } else if (matchattr == container.Entity(cdEntity.LogicalName).PrimaryIdAttribute) { value = cdEntity.Id; } if (value != null) { Query.AppendCondition(qMatch.Criteria, LogicalOperator.And, matchattr, Microsoft.Xrm.Sdk.Query.ConditionOperator.Equal, value); } else { Query.AppendCondition(qMatch.Criteria, LogicalOperator.And, matchattr, Microsoft.Xrm.Sdk.Query.ConditionOperator.Null, null); } } #if DEBUG container.Log($"Finding matches for {cdEntity.LogicalName}:\n{container.ConvertToFetchXml(qMatch)}"); #endif matches = container.RetrieveMultiple(qMatch); } container.EndSection(); return(matches); }
internal OperationsSet2(IExecutionContainer container, string logicalName) : base(container) => this.logicalName = logicalName;
/// <summary> /// </summary> /// <param name="container"></param> /// <param name="query"></param> /// <returns></returns> public static EntityCollection RetrieveMultiple(this IExecutionContainer container, QueryBase query) => container.Service.RetrieveMultiple(query);
internal OperationsSet3(IExecutionContainer container, string logicalName, EntityReference target) : base(container) { this.logicalName = logicalName; this.target = target; }
internal OperationsSet1(IExecutionContainer container, string name) : base(container, name) { }
#pragma warning disable IDE0060 // Remove unused parameter private void ShuffleHandler(IExecutionContainer container, object sender, ShuffleEventArgs e) #pragma warning restore IDE0060 // Remove unused parameter { AddLogText(container, e.Message, e.ReplaceLastMessage); UpdateProgressBars(e.Counters); }
internal InformationBase(IExecutionContainer container) => this.container = container;
/// <summary>Reloads encapsulated Entity from database</summary> /// <param name="container"></param> /// <param name="entity"></param> /// <remarks>ToStringWithEntityName() is replaced with entity.LogicalName</remarks> public static Entity Reload(this IExecutionContainer container, Entity entity) => container.Reload(entity, new ColumnSet());
/// <summary> /// </summary> /// <param name="container"></param> /// <param name="entity"></param> public static void Update(this IExecutionContainer container, Entity entity) { container.Service.Update(entity); container.Log($"Updated {entity.LogicalName} {entity.Id} with {entity.Attributes.Count} attributes"); }
private void ValidatePreReqs(IExecutionContainer container, SolutionBlockImport import, Version thisversion) { if (import.PreRequisites == null) { container.Log("No prereqs for solution import"); return; } container.StartSection("ValidatePreReqs"); var cSolutions = GetExistingSolutions(container); foreach (var prereq in import.PreRequisites) { var valid = false; var name = prereq.Name; var comparer = prereq.Comparer; var version = new Version(); container.Log("Prereq: {0} {1} {2}", name, comparer, version); if (comparer == SolutionVersionComparers.eqthis || comparer == SolutionVersionComparers.gethis) { version = thisversion; comparer = comparer == SolutionVersionComparers.eqthis ? SolutionVersionComparers.eq : comparer == SolutionVersionComparers.gethis ? SolutionVersionComparers.ge : comparer; } else if (comparer != SolutionVersionComparers.any) { version = new Version(prereq.Version.Replace('*', '0')); } foreach (var cdSolution in cSolutions.Entities) { if (cdSolution.GetAttribute("uniquename", "") == name) { container.Log("Found matching solution"); switch (comparer) { case SolutionVersionComparers.any: valid = true; break; case SolutionVersionComparers.eq: valid = new Version(cdSolution.GetAttribute("version", "1.0.0.0")).Equals(version); break; case SolutionVersionComparers.ge: valid = new Version(cdSolution.GetAttribute("version", "<undefined>")) >= version; break; default: throw new ArgumentOutOfRangeException("Comparer", comparer, "Invalid comparer value"); } } if (valid) { break; } } if (valid) { SendLine(container, "Prerequisite {0} {1} {2} is satisfied", name, comparer, version); } else { SendLine(container, "Prerequisite {0} {1} {2} is NOT satisfied", name, comparer, version); throw new Exception("Prerequisite NOT satisfied (" + name + " " + comparer + " " + version + ")"); } } container.EndSection(); }
/// <summary>Encapsulated Retrieve method to be invoked on the service</summary> /// <param name="container"></param> /// <param name="reference"></param> /// <param name="columns">Set of colums with which entity should be reloaded</param> /// <returns></returns> public static Entity Retrieve(this IExecutionContainer container, EntityReference reference, params string[] columns) => container.Service.Retrieve(reference.LogicalName, reference.Id, new ColumnSet(columns));
/// <summary> /// Initiates work with entitites /// </summary> /// <param name="container"></param> /// <param name="target"></param> /// <returns></returns> public static Fluent.Entity.OperationsSet1 Entity(this IExecutionContainer container, Entity target) => new Fluent.Entity.OperationsSet1(container, target);
/// <summary>Encapsulated Retrieve method to be invoked on the service</summary> /// <param name="container"></param> /// <param name="reference"></param> /// <param name="columnSet"></param> /// <returns></returns> public static Entity Retrieve(this IExecutionContainer container, EntityReference reference, ColumnSet columnSet) => container.Service.Retrieve(reference.LogicalName, reference.Id, columnSet);
/// <summary> /// Initiates work with entitites /// </summary> /// <param name="container"></param> /// <param name="logicalName"></param> /// <returns></returns> public static Fluent.Entity.OperationsSet2 Entity(this IExecutionContainer container, string logicalName) => new Fluent.Entity.OperationsSet2(container, logicalName);
/// <summary>Encapsulated Retrieve method to be invoked on the service</summary> /// <param name="container"></param> /// <param name="entityName"></param> /// <param name="id"></param> /// <param name="columns">Set of colums with which entity should be reloaded</param> /// <returns></returns> public static Entity Retrieve(this IExecutionContainer container, string entityName, Guid id, params string[] columns) => container.Service.Retrieve(entityName, id, new ColumnSet(columns));
/// <summary> /// Initiates work with principals which is followed with access related opetations: Grant / Revoke / Assign /// </summary> /// <param name="container"></param> /// <param name="principal"></param> /// <returns></returns> public static Fluent.Access.OperationsSet1 Principal(this IExecutionContainer container, EntityReference principal) => new Fluent.Access.OperationsSet1(container, principal);
/// <summary>Encapsulated Retrieve method to be invoked on the service</summary> /// <param name="container"></param> /// <param name="entityName"></param> /// <param name="id"></param> /// <param name="columnSet"></param> /// <returns></returns> public static Entity Retrieve(this IExecutionContainer container, string entityName, Guid id, ColumnSet columnSet) => container.Service.Retrieve(entityName, id, columnSet);