private static void SelectAttributes(CintDynEntityCollection cExportEntities, List <string> lAttributes, List <string> lNullAttributes) { foreach (var cde in cExportEntities) { var i = 0; var x = new List <string>(cde.Attributes.Keys); while (i < cde.Attributes.Count) { var attr = x[i]; if (attr != cde.PrimaryIdAttribute && !IncludeAttribute(attr, lAttributes)) { cde.Attributes.Remove(attr); x.Remove(attr); } else { i++; } } foreach (var nullattribute in lNullAttributes) { if (!cde.Contains(nullattribute)) { cde.Entity.Attributes.Add(nullattribute, null); } } } }
/// <summary> /// /// </summary> /// <param name="blocks"></param> /// <param name="type"></param> /// <param name="delimeter"></param> /// <returns></returns> public Dictionary <string, XmlDocument> SplitFiles(ShuffleBlocks blocks, SerializationType type, char delimeter) { log.StartSection("Start SplitFiles"); var dictionarySplitFiles = new Dictionary <string, XmlDocument>(); if (blocks.Count > 0) { foreach (var blockName in blocks.Keys) { var block = blocks[blockName]; foreach (var item in block) { //Build path to use later when writing to disk string path = blockName; path += "\\" + item.Id; // Somehow create a single entity record shuffleBlock var singleShuffleBlock = new ShuffleBlocks(); var entityCollection = new CintDynEntityCollection(); singleShuffleBlock.Add(blockName, entityCollection); entityCollection.Add(item); dictionarySplitFiles.Add(path, Serialize(singleShuffleBlock, type, delimeter)); } } } log.EndSection(); return(dictionarySplitFiles); }
private CintDynEntityCollection GetMatchingRecords(CintDynEntity cdEntity, List <string> matchattributes, List <string> updateattributes, bool preretrieveall, ref CintDynEntityCollection cAllRecordsToMatch) { log.StartSection(MethodBase.GetCurrentMethod().Name); CintDynEntityCollection matches = null; var allattributes = new List <string>(); allattributes.Add(cdEntity.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(allattributes, cdEntity); } matches = GetMatchingRecordsFromPreRetrieved(matchattributes, cdEntity, cAllRecordsToMatch); } else { QueryExpression qMatch = new QueryExpression(cdEntity.Name); // 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 qMatch.ColumnSet = new ColumnSet(allattributes.ToArray()); foreach (var matchattr in matchattributes) { object value = null; if (cdEntity.Entity.Contains(matchattr)) { value = CintEntity.AttributeToBaseType(cdEntity.Entity[matchattr]); } else if (matchattr == cdEntity.PrimaryIdAttribute) { value = cdEntity.Id; } if (value != null) { CintQryExp.AppendCondition(qMatch.Criteria, LogicalOperator.And, matchattr, Microsoft.Xrm.Sdk.Query.ConditionOperator.Equal, value); } else { CintQryExp.AppendCondition(qMatch.Criteria, LogicalOperator.And, matchattr, Microsoft.Xrm.Sdk.Query.ConditionOperator.Null, null); } } #if DEBUG log.Log("Finding matches for {0}:\n{1}", cdEntity, CintQryExp.ConvertToFetchXml(qMatch, crmsvc)); #endif matches = CintDynEntity.RetrieveMultiple(crmsvc, qMatch, log); } log.EndSection(); return(matches); }
private CintDynEntityCollection GetExistingSolutions() { CintDynEntityCollection cSolutions = CintDynEntity.RetrieveMultiple(crmsvc, "solution", new string[] { "isvisible" }, new object[] { true }, new ColumnSet("solutionid", "uniquename", "friendlyname", "version", "ismanaged"), log); return(cSolutions); }
private CintDynEntityCollection GetAllRecordsForMatching(List <string> allattributes, CintDynEntity cdEntity) { log.StartSection(MethodBase.GetCurrentMethod().Name); QueryExpression qMatch = new QueryExpression(cdEntity.Name); qMatch.ColumnSet = new ColumnSet(allattributes.ToArray()); #if DEBUG log.Log("Retrieving all records for {0}:\n{1}", cdEntity.Name, CintQryExp.ConvertToFetchXml(qMatch, crmsvc)); #endif CintDynEntityCollection matches = CintDynEntity.RetrieveMultiple(crmsvc, qMatch, log); SendLine("Pre-retrieved {0} records for matching", matches.Count); log.EndSection(); return(matches); }
internal static void AddToSolution(this CintContainer container, CintDynEntityCollection resources, string solutionUniqueName) { foreach (var resource in resources) { var request = new AddSolutionComponentRequest { AddRequiredComponents = false, ComponentId = resource.Id, ComponentType = SolutionComponentType.WebResource, SolutionUniqueName = solutionUniqueName }; container.Service.Execute(request); } }
private List <string> GetUpdateAttributes(CintDynEntityCollection entities) { var result = new List <string>(); foreach (var entity in entities) { foreach (var attribute in entity.Attributes.Keys) { if (!result.Contains(attribute)) { result.Add(attribute); } } } return(result); }
private CintDynEntityCollection GetMatchingRecordsFromPreRetrieved(List <string> matchattributes, CintDynEntity cdEntity, CintDynEntityCollection cAllRecordsToMatch) { log.StartSection(MethodBase.GetCurrentMethod().Name); log.Log("Searching matches for: {0} {1}", cdEntity.Id, cdEntity); var result = new CintDynEntityCollection(); foreach (var cdRecord in cAllRecordsToMatch) { if (EntityAttributesEqual(matchattributes, cdEntity, cdRecord)) { result.Add(cdRecord); log.Log("Found match: {0} {1}", cdRecord.Id, cdRecord); } } log.Log("Returned matches: {0}", result.Count); log.EndSection(); return(result); }
private CintDynEntity GetAndVerifySolutionForExport(string name) { CintDynEntityCollection cSolutions = CintDynEntity.RetrieveMultiple(crmsvc, "solution", new string[] { "isvisible", "uniquename" }, new object[] { true, name }, new ColumnSet("solutionid", "friendlyname", "version", "ismanaged"), log); if (cSolutions.Count == 0) { throw new ArgumentOutOfRangeException("SolutionUniqueName", name, "Cannot find solution"); } if (cSolutions.Count > 1) { throw new ArgumentOutOfRangeException("SolutionUniqueName", name, "Found " + cSolutions.Count.ToString() + " matching solutions"); } CintDynEntity cdSolution = cSolutions[0]; return(cdSolution); }
private static void AddRelationFilter(ShuffleBlocks blocks, XmlNode xRelation, XmlNode xEntity, ILoggable log) { if (blocks != null && blocks.Count > 0) { var block = CintXML.GetAttribute(xRelation, "Block"); var attribute = CintXML.GetAttribute(xRelation, "Attribute"); var pkattribute = CintXML.GetAttribute(xRelation, "PK-Attribute"); var includenull = CintXML.GetBoolAttribute(xRelation, "IncludeNull", false); List <string> ids = new List <string>(); CintDynEntityCollection parentcoll = blocks.ContainsKey(block) ? blocks[block] : null; if (parentcoll != null && parentcoll.Count > 0) { foreach (CintDynEntity parent in parentcoll) { if (string.IsNullOrEmpty(pkattribute)) { ids.Add(parent.Id.ToString()); } else { ids.Add(parent.Property <EntityReference>(pkattribute, new EntityReference()).Id.ToString()); } } } else { // Adding temp guid to indicate "no matches", as ConditionOperator.In will fail if no values are given ids.Add(new Guid().ToString()); } if (!includenull) { CintFetchXML.AppendFilter(xEntity, "and", attribute, "in", ids.ToArray()); } else { var xFilter = CintFetchXML.AppendFilter(xEntity, "or"); CintFetchXML.AppendCondition(xFilter, attribute, "null"); CintFetchXML.AppendCondition(xFilter, attribute, "in", ids.ToArray()); } log.Log("Adding relation condition for {0} in {1} values in {2}.{3}", attribute, ids.Count, block, pkattribute); } }
private SolutionImportConditions CheckIfImportRequired(XmlNode xImport, string name, Version thisversion) { log.StartSection("CheckIfImportRequired"); SolutionImportConditions result = SolutionImportConditions.Create; bool overwritesame = CintXML.GetBoolAttribute(xImport, "OverwriteSameVersion", true); bool overwritenewer = CintXML.GetBoolAttribute(xImport, "OverwriteNewerVersion", false); CintDynEntityCollection cSolutions = GetExistingSolutions(); foreach (CintDynEntity cdSolution in cSolutions) { if (cdSolution.Property("uniquename", "") == name) { // Now we have found the same solution in target environment result = SolutionImportConditions.Update; var existingversion = new Version(cdSolution.Property("version", "1.0.0.0")); log.Log("Existing solution has version: {0}", existingversion); var comparison = thisversion.CompareTo(existingversion); if (!overwritesame && comparison == 0) { result = SolutionImportConditions.Skip; SendLine("Solution {0} {1} already exists in target", name, thisversion); } else if (!overwritenewer && comparison < 0) { result = SolutionImportConditions.Skip; SendLine("Existing solution {0} {1} is newer than {2}", name, existingversion, thisversion); } else if (existingversion == thisversion) { SendLine("Updating version {0}", thisversion); } else { SendLine("Replacing version {0} with {1}", existingversion, thisversion); } break; } } log.Log("Import Condition: {0}", result); log.EndSection(); return(result); }
private void GetSolutions() { if (Service == null) { return; } if (working) { return; } working = true; WorkAsync(new WorkAsyncInfo("Loading solutions", (eventargs) => { var svc = new CrmServiceProxy(Service); var log = new PluginLogger("ShuffleBuilder", true, ""); try { solutionsUnmanaged = CintDynEntity.RetrieveMultiple(svc, "solution", new string[] { "isvisible", "ismanaged" }, new object[] { true, false }, new ColumnSet("solutionid", "uniquename", "friendlyname", "version"), log); } finally { log.CloseLog(); } }) { PostWorkCallBack = (completedargs) => { if (completedargs.Error != null) { MessageBox.Show(completedargs.Error.Message); } working = false; } }); }
internal static void PublishWebResources(this CintContainer container, CintDynEntityCollection resources) { try { string idsXml = string.Empty; foreach (var resource in resources) { idsXml += string.Format("<webresource>{0}</webresource>", resource.Id.ToString("B")); } var pxReq1 = new PublishXmlRequest { ParameterXml = string.Format("<importexportxml><webresources>{0}</webresources></importexportxml>", idsXml) }; container.Service.Execute(pxReq1); } catch (Exception error) { throw new Exception("Error while publishing web resources: " + error.Message); } }
private Tuple <int, int, int, int, int, EntityReferenceCollection> ImportDataBlock(XmlNode xBlock, CintDynEntityCollection cEntities) { log.StartSection("ImportDataBlock"); int created = 0; int updated = 0; int skipped = 0; int deleted = 0; int failed = 0; EntityReferenceCollection references = new EntityReferenceCollection(); string name = CintXML.GetAttribute(xBlock, "Name"); log.Log("Block: {0}", name); SendStatus(name, null); SendLine(); switch (xBlock.Name) { case "DataBlock": string type = CintXML.GetAttribute(xBlock, "Type"); XmlNode xImport = CintXML.FindChild(xBlock, "Import"); if (xImport != null) { var includeid = CintXML.GetBoolAttribute(xImport, "CreateWithId", false); var save = CintXML.GetAttribute(xImport, "Save"); var delete = CintXML.GetAttribute(xImport, "Delete"); var updateinactive = CintXML.GetBoolAttribute(xImport, "UpdateInactive", false); var updateidentical = CintXML.GetBoolAttribute(xImport, "UpdateIdentical", false); var deprecatedoverwrite = CintXML.GetAttribute(xImport, "Overwrite"); if (!string.IsNullOrWhiteSpace(deprecatedoverwrite)) { SendLine("DEPRECATED use of attribute Overwrite!"); bool overwrite = CintXML.GetBoolAttribute(xImport, "Overwrite", true); save = overwrite ? "CreateUpdate" : "CreateOnly"; } if (string.IsNullOrWhiteSpace(save)) { // Default save = "CreateUpdate"; } if (string.IsNullOrWhiteSpace(delete)) { // Default delete = "None"; } XmlNode xMatch = CintXML.FindChild(xImport, "Match"); var matchattributes = GetMatchAttributes(xMatch); var updateattributes = !updateidentical?GetUpdateAttributes(cEntities) : new List <string>(); var preretrieveall = xMatch != null?CintXML.GetBoolAttribute(xMatch, "PreRetrieveAll", false) : false; SendLine(); SendLine("Importing block {0} - {1} records ", name, cEntities.Count); var i = 1; if (delete == "All" && (matchattributes.Count == 0)) { // All records shall be deleted, no match attribute defined, so just get all and delete all string entity = CintXML.GetAttribute(xBlock, "Entity"); var qDelete = new QueryExpression(entity); qDelete.ColumnSet.AddColumn(crmsvc.PrimaryAttribute(entity, log)); var deleterecords = CintDynEntity.RetrieveMultiple(crmsvc, qDelete, log); SendLine("Deleting ALL {0} - {1} records", entity, deleterecords.Count); foreach (var record in deleterecords) { SendLine("{0:000} Deleting existing: {1}", i, record); try { record.Delete(); deleted++; } catch (FaultException <OrganizationServiceFault> ex) { if (ex.Message.ToUpperInvariant().Contains("DOES NOT EXIST")) { // This may happen through delayed cascade delete in CRM SendLine(" ...already deleted"); } else { throw; } } i++; } } int totalRecords = cEntities.Count; i = 1; CintDynEntityCollection cAllRecordsToMatch = null; foreach (CintDynEntity cdEntity in cEntities) { string unique = cdEntity.Id.ToString(); SendStatus(-1, -1, totalRecords, i); try { Guid oldid = cdEntity.Id; Guid newid = Guid.Empty; ReplaceGuids(cdEntity, includeid); ReplaceUpdateInfo(cdEntity); unique = GetEntityDisplayString(xMatch, cdEntity); SendStatus(null, unique); if (type == "Entity" || string.IsNullOrEmpty(type)) { #region Entity if (matchattributes.Count == 0) { if (save == "Never" || save == "UpdateOnly") { skipped++; SendLine("{0:000} Not saving: {1}", i, unique); } else { if (!includeid) { cdEntity.Id = Guid.Empty; } if (SaveEntity(cdEntity, null, updateinactive, updateidentical, i, unique)) { created++; newid = cdEntity.Id; references.Add(cdEntity.Entity.ToEntityReference()); } } } else { var matches = GetMatchingRecords(cdEntity, matchattributes, updateattributes, preretrieveall, ref cAllRecordsToMatch); if (delete == "All" || (matches.Count == 1 && delete == "Existing")) { foreach (CintDynEntity cdMatch in matches) { SendLine("{0:000} Deleting existing: {1}", i, unique); try { cdMatch.Delete(); deleted++; } catch (FaultException <OrganizationServiceFault> ex) { if (ex.Message.ToUpperInvariant().Contains("DOES NOT EXIST")) { // This may happen through cascade delete in CRM SendLine(" ...already deleted"); } else { throw; } } } matches.Clear(); } if (matches.Count == 0) { if (save == "Never" || save == "UpdateOnly") { skipped++; SendLine("{0:000} Not creating: {1}", i, unique); } else { if (!includeid) { cdEntity.Id = Guid.Empty; } if (SaveEntity(cdEntity, null, updateinactive, updateidentical, i, unique)) { created++; newid = cdEntity.Id; references.Add(cdEntity.Entity.ToEntityReference()); } } } else if (matches.Count == 1) { var match = matches[0]; newid = match.Id; if (save == "CreateUpdate" || save == "UpdateOnly") { if (SaveEntity(cdEntity, match, updateinactive, updateidentical, i, unique)) { updated++; references.Add(cdEntity.Entity.ToEntityReference()); } else { skipped++; } } else { skipped++; SendLine("{0:000} Exists: {1}", i, unique); } } else { failed++; SendLine("Import object matches {0} records in target database!", matches.Count); SendLine(unique); } } if (!oldid.Equals(Guid.Empty) && !newid.Equals(Guid.Empty) && !oldid.Equals(newid) && !guidmap.ContainsKey(oldid)) { log.Log("Mapping IDs: {0} ==> {1}", oldid, newid); guidmap.Add(oldid, newid); } #endregion Entity } else if (type == "Intersect") { #region Intersect if (cdEntity.Attributes.Count != 2) { throw new ArgumentOutOfRangeException("Attributes", cdEntity.Attributes.Count, "Invalid Attribute count for intersect object"); } string intersect = CintXML.GetAttribute(xBlock, "IntersectName"); if (string.IsNullOrEmpty(intersect)) { intersect = cdEntity.Name; } EntityReference ref1 = (EntityReference)cdEntity.Attributes.ElementAt(0).Value; EntityReference ref2 = (EntityReference)cdEntity.Attributes.ElementAt(1).Value; CintDynEntity party1 = CintDynEntity.InitFromNameAndId(ref1.LogicalName, ref1.Id, crmsvc, log); CintDynEntity party2 = CintDynEntity.InitFromNameAndId(ref2.LogicalName, ref2.Id, crmsvc, log); try { party1.Associate(party2, intersect); created++; SendLine("{0} Associated: {1}", i.ToString().PadLeft(3, '0'), name); } catch (Exception ex) { if (ex.Message.Contains("duplicate")) { SendLine("{0} Association exists: {1}", i.ToString().PadLeft(3, '0'), name); skipped++; } else { throw; } } #endregion Intersect } } catch (Exception ex) { failed++; SendLine("\n*** Error record: {0} ***\n{1}", unique, ex.Message); log.Log(ex); if (stoponerror) { throw; } } i++; } SendLine("Created: {0} Updated: {1} Skipped: {2} Deleted: {3} Failed: {4}", created, updated, skipped, deleted, failed); } break; default: throw new ArgumentOutOfRangeException("Type", xBlock.Name, "Invalid Block type"); } log.EndSection(); return(new Tuple <int, int, int, int, int, EntityReferenceCollection>(created, updated, skipped, deleted, failed, references)); }
/// <summary> /// Export entities from CRM to dictionary of blocks with entities /// </summary> /// <returns>Blocks with exported entities</returns> public ShuffleBlocks ExportFromCRM() { log.StartSection("ExportFromCRM"); if (definition == null) { throw new ArgumentNullException("Definition", "Shuffle definition must be specified to export data"); } ShuffleBlocks blocks = new ShuffleBlocks(); ExistingSolutionVersions = null; XmlNode xRoot = CintXML.FindChild(definition, "ShuffleDefinition"); XmlNode xBlocks = CintXML.FindChild(xRoot, "Blocks"); if (xBlocks != null) { stoponerror = CintXML.GetBoolAttribute(xRoot, "StopOnError", false); timeout = CintXML.GetIntAttribute(xRoot, "Timeout", -1); double savedtimeout = -1; if (timeout > -1) { SendLine("Setting timeout: {0} minutes", timeout); OrganizationServiceProxy orgsvcpxy = crmsvc.GetService <OrganizationServiceProxy>(); savedtimeout = orgsvcpxy.Timeout.TotalMinutes; orgsvcpxy.Timeout = new TimeSpan(0, timeout, 0); } int totalBlocks = xBlocks.ChildNodes.Count; int currentBlock = 0; foreach (XmlNode xBlock in xBlocks.ChildNodes) { currentBlock++; SendStatus(totalBlocks, currentBlock, -1, -1); if (xBlock.NodeType == XmlNodeType.Element) { switch (xBlock.Name) { case "DataBlock": CintDynEntityCollection cExported = ExportDataBlock(blocks, xBlock); string name = CintXML.GetAttribute(xBlock, "Name"); if (cExported != null) { if (blocks.ContainsKey(name)) { SendLine("Block already added: {0}", name); } else { blocks.Add(name, cExported); } } break; case "SolutionBlock": if (ExistingSolutionVersions == null) { GetCurrentVersions(); } ExportSolutionBlock(xBlock); break; } } } SendStatus(0, 0, 0, 0); if (savedtimeout > -1) { OrganizationServiceProxy orgsvcpxy = crmsvc.GetService <OrganizationServiceProxy>(); orgsvcpxy.Timeout = new TimeSpan(0, (int)savedtimeout, 0); } } log.EndSection(); return(blocks); }
/// <summary> /// Deserialize xml/string to blocks with entities /// </summary> /// <param name="serialized"></param> /// <returns>Optional, only required for SerializationType: Text</returns> public ShuffleBlocks Deserialize(XmlDocument serialized) { log.StartSection("Deserialize"); ShuffleBlocks result = new ShuffleBlocks(); if (serialized != null) { XmlNode root = CintXML.FindChild(serialized, "ShuffleData"); string sertype = CintXML.GetAttribute(root, "Type"); SendLine("Deserialize from {0}", sertype); if (sertype == SerializationType.Full.ToString() || sertype == SerializationType.Simple.ToString() || sertype == SerializationType.SimpleNoId.ToString() || sertype == SerializationType.SimpleWithValue.ToString() || sertype == SerializationType.Explicit.ToString()) { foreach (XmlNode xBlock in root.ChildNodes) { if (xBlock.NodeType == XmlNodeType.Element && xBlock.Name == "Block" && xBlock.ChildNodes.Count == 1) { string name = CintXML.GetAttribute(xBlock, "Name"); XmlDocument xml = new XmlDocument(); xml.AppendChild(xml.ImportNode(xBlock.ChildNodes[0], true)); CintDynEntityCollection cEntities = new CintDynEntityCollection(xml, crmsvc, log); SendLine("Block {0}: {1} records", name, cEntities.Count); result.Add(name, cEntities); } } } else if (sertype == SerializationType.Text.ToString()) { string strdelimeter = CintXML.GetAttribute(root, "Delimeter"); char delimeter = strdelimeter.Length == 1 ? strdelimeter[0] : '\t'; XmlNode xText = CintXML.FindChild(root, "Text"); StringReader reader = new StringReader(xText.InnerText); int line = 0; string name = ""; StringBuilder serializedblock = null; string current = reader.ReadLine(); while (current != null) { log.Log("Line {0:000}: {1}", line, current); if (current.StartsWith("<<<") && current.Contains(">>>")) { log.Log("Block start"); if (!string.IsNullOrWhiteSpace(name) && serializedblock != null) { CintDynEntityCollection cEntities = new CintDynEntityCollection(serializedblock.ToString(), delimeter, crmsvc, log); result.Add(name, cEntities); SendLine("Block {0}: {1} records", name, cEntities.Count); } name = current.Substring(3); name = name.Substring(0, name.IndexOf(">>>", StringComparison.Ordinal)); serializedblock = new StringBuilder(); } else { serializedblock.AppendLine(current); } current = reader.ReadLine(); line++; } if (!string.IsNullOrWhiteSpace(serializedblock.ToString())) { CintDynEntityCollection cEntities = new CintDynEntityCollection(serializedblock.ToString(), delimeter, crmsvc, log); result.Add(name, cEntities); SendLine("Block {0}: {1} records", name, cEntities.Count); } } } log.EndSection(); return(result); }
private CintDynEntityCollection ExportDataBlock(ShuffleBlocks blocks, DataBlock block) { log.StartSection("ExportDataBlock"); log.Log("Block: {0}", block.Name); CintDynEntityCollection cExportEntities = null; if (block.Export != null) { #region Define attributes var attributes = block.Export.Items.Where(i => i is DataBlockExportAttributes).FirstOrDefault() as DataBlockExportAttributes; var allcolumns = false; var lAttributes = new List <string>(); var lNullAttributes = new List <string>(); if (attributes != null) { foreach (var attribute in attributes.Attribute) { var attr = attribute.Name; log.Log("Adding column: {0}", attr); lAttributes.Add(attr.Replace("*", "%")); if (attr.Contains("*")) { allcolumns = true; log.Log("Found wildcard"); } else { if (attribute.IncludeNull) { lNullAttributes.Add(attr); } } } } else { allcolumns = true; lAttributes.Add("*"); log.Log("Attributes not specified, retrieving all"); } #endregion Define attributes var fetchxml = block.Export.Items.Where(i => i is string).FirstOrDefault() as string; if (!string.IsNullOrWhiteSpace(fetchxml)) { log.StartSection("Export entity using FetchXML"); #if DEBUG log.Log("FetchXML:\n{0}", fetchxml); #endif cExportEntities = CintDynEntity.RetrieveMultiple(crmsvc, new FetchExpression(fetchxml), log); log.EndSection(); } else if (!block.TypeSpecified || block.Type == EntityTypes.Entity) { #region QueryExpression Entity log.StartSection("Export entity " + block.Entity); var qExport = new QueryExpression(block.Entity); if (block.Export.ActiveOnly) { CintQryExp.AppendConditionActive(qExport.Criteria); } if (block.Relation != null) { foreach (var relation in block.Relation) { AddRelationFilter(blocks, block.Entity, relation, qExport.Criteria, log); } } foreach (var filter in block.Export.Items.Where(i => i is DataBlockExportFilter).Cast <DataBlockExportFilter>()) { AddFilter(qExport, filter); } foreach (var sort in block.Export.Items.Where(i => i is DataBlockExportSort).Cast <DataBlockExportSort>()) { qExport.AddOrder(sort.Attribute, sort.Type == SortTypes.Desc ? OrderType.Descending : OrderType.Ascending); } if (allcolumns) { qExport.ColumnSet = new ColumnSet(true); } else { foreach (var attr in lAttributes) { qExport.ColumnSet.AddColumn(attr); } } #if DEBUG log.Log("Converting to FetchXML"); try { var fetch = CintQryExp.ConvertToFetchXml(qExport, crmsvc); log.Log("Exporting {0}:\n{1}", block.Entity, fetch); } catch (Exception ex) { log.Log("Conversion error:"); log.Log(ex); } #endif cExportEntities = CintDynEntity.RetrieveMultiple(crmsvc, qExport, log); if (allcolumns) { SelectAttributes(cExportEntities, lAttributes, lNullAttributes); } SendLine("Block {0} - {1} records", block.Name, cExportEntities.Count); log.EndSection(); #endregion QueryExpression Entity } else if (block.Type == EntityTypes.Intersect) { #region FetchXML Intersect log.StartSection("Export intersect " + block.Entity); var xDoc = new XmlDocument(); var xEntity = CintFetchXML.Create(xDoc, block.Entity); CintFetchXML.AddAttribute(xEntity, lAttributes.ToArray()); if (block.Relation != null) { foreach (var relation in block.Relation) { AddRelationFilter(blocks, relation, xEntity, log); } } var fetch = xDoc.OuterXml; fetch = fetch.Replace("<fetch ", "<fetch {0} {1} "); // Detta för att se till att CrmServiceProxy.RetrieveMultiple kan hantera paging #if DEBUG log.Log("Exporting intersect entity {0}\n{1}", block.Entity, fetch); #endif var qExport = new FetchExpression(fetch); cExportEntities = CintDynEntity.RetrieveMultiple(crmsvc, qExport, log); foreach (var cde in cExportEntities) { var newattributes = new List <KeyValuePair <string, object> >(); foreach (var attr in cde.Attributes) { if (attr.Value is Guid) { var attrname = attr.Key; var relatedentity = attrname.Substring(0, attrname.Length - (attrname.EndsWith("idone") || attrname.EndsWith("idtwo") ? 5 : 2)); newattributes.Add(new KeyValuePair <string, object>(attrname, new EntityReference(relatedentity, (Guid)attr.Value))); } } foreach (var newattr in newattributes) { if (!newattr.Key.Equals(cde.PrimaryIdAttribute)) { cde.AddProperty(newattr.Key, newattr.Value); } } } log.EndSection(); #endregion FetchXML Intersect } log.Log("Returning {0} records", cExportEntities.Count); } log.EndSection(); return(cExportEntities); }
private CintDynEntityCollection ExportDataBlock(ShuffleBlocks blocks, XmlNode xBlock) { log.StartSection("ExportDataBlock"); string name = CintXML.GetAttribute(xBlock, "Name"); log.Log("Block: {0}", name); CintDynEntityCollection cExportEntities = null; if (xBlock.Name != "DataBlock") { throw new ArgumentOutOfRangeException("Type", xBlock.Name, "Invalid Block type"); } string entity = CintXML.GetAttribute(xBlock, "Entity"); string type = CintXML.GetAttribute(xBlock, "Type"); XmlNode xExport = CintXML.FindChild(xBlock, "Export"); if (xExport != null) { if (string.IsNullOrEmpty(entity)) { entity = CintXML.GetAttribute(xExport, "Entity"); } #region Define attributes XmlNode xAttributes = CintXML.FindChild(xExport, "Attributes"); bool allcolumns = false; List <string> lAttributes = new List <string>(); List <string> lNullAttributes = new List <string>(); if (xAttributes != null) { foreach (XmlNode xAttr in xAttributes.ChildNodes) { if (xAttr.Name == "Attribute") { string attr = CintXML.GetAttribute(xAttr, "Name"); log.Log("Adding column: {0}", attr); lAttributes.Add(attr.Replace("*", "%")); if (attr.Contains("*")) { allcolumns = true; log.Log("Found wildcard"); } else { bool includenull = CintXML.GetBoolAttribute(xAttr, "IncludeNull", false); if (includenull) { lNullAttributes.Add(attr); } } } } } else { allcolumns = true; lAttributes.Add("*"); log.Log("Attributes not specified, retrieving all"); } #endregion Define attributes if (type == "Entity" || string.IsNullOrEmpty(type)) { #region QueryExpression Entity log.StartSection("Export entity " + entity); QueryExpression qExport = new QueryExpression(entity); if (CintXML.GetBoolAttribute(xExport, "ActiveOnly", true)) { CintQryExp.AppendConditionActive(qExport.Criteria); } foreach (var xBlockChild in xBlock.ChildNodes.Cast <XmlNode>()) { if (xBlockChild.Name == "Relation") { AddRelationFilter(blocks, xBlockChild, qExport.Criteria, log); } } foreach (XmlNode xExpProp in xExport.ChildNodes) { if (xExport.NodeType == XmlNodeType.Element) { switch (xExpProp.Name) { case "#comment": case "Attributes": break; case "Filter": AddFilter(qExport, xExpProp); break; case "Sort": qExport.AddOrder( CintXML.GetAttribute(xExpProp, "Attribute"), CintXML.GetAttribute(xExpProp, "Type") == "Desc" ? OrderType.Descending : OrderType.Ascending); break; default: throw new ArgumentOutOfRangeException("Name", xExpProp.Name, "Invalid subitem to export block " + name); } } } if (allcolumns) { qExport.ColumnSet = new ColumnSet(true); } else { foreach (string attr in lAttributes) { qExport.ColumnSet.AddColumn(attr); } } #if DEBUG log.Log("Converting to FetchXML"); try { var fetch = CintQryExp.ConvertToFetchXml(qExport, crmsvc); log.Log("Exporting {0}:\n{1}", entity, fetch); } catch (Exception ex) { log.Log("Conversion error:"); log.Log(ex); } #endif cExportEntities = CintDynEntity.RetrieveMultiple(crmsvc, qExport, log); if (allcolumns) { SelectAttributes(cExportEntities, lAttributes, lNullAttributes); } SendLine("Block {0} - {1} records", name, cExportEntities.Count); log.EndSection(); #endregion QueryExpression Entity } else if (type == "Intersect") { #region FetchXML Intersect log.StartSection("Export intersect " + entity); XmlDocument xDoc = new XmlDocument(); XmlNode xEntity = CintFetchXML.Create(xDoc, entity); CintFetchXML.AddAttribute(xEntity, lAttributes.ToArray()); foreach (var xBlockChild in xBlock.ChildNodes.Cast <XmlNode>()) { if (xBlockChild.Name == "Relation") { AddRelationFilter(blocks, xBlockChild, xEntity, log); } } var fetch = xDoc.OuterXml; fetch = fetch.Replace("<fetch ", "<fetch {0} {1} "); // Detta för att se till att CrmServiceProxy.RetrieveMultiple kan hantera paging #if DEBUG log.Log("Exporting intersect entity {0}\n{1}", entity, fetch); #endif var qExport = new FetchExpression(fetch); cExportEntities = CintDynEntity.RetrieveMultiple(crmsvc, qExport, log); foreach (var cde in cExportEntities) { List <KeyValuePair <string, object> > newattributes = new List <KeyValuePair <string, object> >(); foreach (var attr in cde.Attributes) { if (attr.Value is Guid) { var attrname = attr.Key; string relatedentity = attrname.Substring(0, attrname.Length - (attrname.EndsWith("idone") || attrname.EndsWith("idtwo") ? 5 : 2)); newattributes.Add(new KeyValuePair <string, object>(attrname, new EntityReference(relatedentity, (Guid)attr.Value))); } } foreach (var newattr in newattributes) { if (!newattr.Key.Equals(cde.PrimaryIdAttribute)) { cde.AddProperty(newattr.Key, newattr.Value); } } } log.EndSection(); #endregion FetchXML Intersect } log.Log("Returning {0} records", cExportEntities.Count); } log.EndSection(); return(cExportEntities); }
private Tuple <int, int, int, int, int, EntityReferenceCollection> ImportDataBlock(DataBlock block, CintDynEntityCollection cEntities) { log.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; log.Log("Block: {0}", name); SendStatus(name, null); SendLine(); 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("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(); SendLine("Importing block {0} - {1} records ", name, cEntities.Count); 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(crmsvc.PrimaryAttribute(entity, log)); var deleterecords = CintDynEntity.RetrieveMultiple(crmsvc, qDelete, log); SendLine("Deleting ALL {0} - {1} records", entity, deleterecords.Count); foreach (var record in deleterecords) { SendLine("{0:000} Deleting existing: {1}", i, record); try { record.Delete(); deleted++; } catch (FaultException <OrganizationServiceFault> ex) { if (ex.Message.ToUpperInvariant().Contains("DOES NOT EXIST")) { // This may happen through delayed cascade delete in CRM SendLine(" ...already deleted"); } else { throw; } } i++; } } var totalRecords = cEntities.Count; i = 1; CintDynEntityCollection cAllRecordsToMatch = null; foreach (var cdEntity in cEntities) { var unique = cdEntity.Id.ToString(); SendStatus(-1, -1, totalRecords, i); try { var oldid = cdEntity.Id; var newid = Guid.Empty; ReplaceGuids(cdEntity, includeid); ReplaceUpdateInfo(cdEntity); unique = GetEntityDisplayString(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("{0:000} Not saving: {1}", i, unique); } else { if (!includeid) { cdEntity.Id = Guid.Empty; } if (SaveEntity(cdEntity, null, updateinactive, updateidentical, i, unique)) { created++; newid = cdEntity.Id; references.Add(cdEntity.Entity.ToEntityReference()); } } } else { var matches = GetMatchingRecords(cdEntity, matchattributes, updateattributes, preretrieveall, ref cAllRecordsToMatch); if (delete == DeleteTypes.All || (matches.Count == 1 && delete == DeleteTypes.Existing)) { foreach (var cdMatch in matches) { SendLine("{0:000} Deleting existing: {1}", i, unique); try { cdMatch.Delete(); deleted++; } catch (FaultException <OrganizationServiceFault> ex) { if (ex.Message.ToUpperInvariant().Contains("DOES NOT EXIST")) { // This may happen through cascade delete in CRM SendLine(" ...already deleted"); } else { throw; } } } matches.Clear(); } if (matches.Count == 0) { if (save == SaveTypes.Never || save == SaveTypes.UpdateOnly) { skipped++; SendLine("{0:000} Not creating: {1}", i, unique); } else { if (!includeid) { cdEntity.Id = Guid.Empty; } if (SaveEntity(cdEntity, null, updateinactive, updateidentical, i, unique)) { created++; newid = cdEntity.Id; references.Add(cdEntity.Entity.ToEntityReference()); } } } else if (matches.Count == 1) { var match = matches[0]; newid = match.Id; if (save == SaveTypes.CreateUpdate || save == SaveTypes.UpdateOnly) { if (SaveEntity(cdEntity, match, updateinactive, updateidentical, i, unique)) { updated++; references.Add(cdEntity.Entity.ToEntityReference()); } else { skipped++; } } else { skipped++; SendLine("{0:000} Exists: {1}", i, unique); } } else { failed++; SendLine("Import object matches {0} records in target database!", matches.Count); SendLine(unique); } } if (!oldid.Equals(Guid.Empty) && !newid.Equals(Guid.Empty) && !oldid.Equals(newid) && !guidmap.ContainsKey(oldid)) { log.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.Name; } var ref1 = (EntityReference)cdEntity.Attributes.ElementAt(0).Value; var ref2 = (EntityReference)cdEntity.Attributes.ElementAt(1).Value; var party1 = CintDynEntity.InitFromNameAndId(ref1.LogicalName, ref1.Id, crmsvc, log); var party2 = CintDynEntity.InitFromNameAndId(ref2.LogicalName, ref2.Id, crmsvc, log); try { party1.Associate(party2, intersect); created++; SendLine("{0} Associated: {1}", i.ToString().PadLeft(3, '0'), name); } catch (Exception ex) { if (ex.Message.Contains("duplicate")) { SendLine("{0} Association exists: {1}", i.ToString().PadLeft(3, '0'), name); skipped++; } else { throw; } } #endregion Intersect } } catch (Exception ex) { failed++; SendLine("\n*** Error record: {0} ***\n{1}", unique, ex.Message); log.Log(ex); if (stoponerror) { throw; } } i++; } SendLine("Created: {0} Updated: {1} Skipped: {2} Deleted: {3} Failed: {4}", created, updated, skipped, deleted, failed); } log.EndSection(); return(new Tuple <int, int, int, int, int, EntityReferenceCollection>(created, updated, skipped, deleted, failed, references)); }
private void AddRelationFilter(ShuffleBlocks blocks, XmlNode xRelation, FilterExpression filter, ILoggable log) { log.StartSection(MethodBase.GetCurrentMethod().Name); if (blocks != null && blocks.Count > 0) { var block = CintXML.GetAttribute(xRelation, "Block"); var attribute = CintXML.GetAttribute(xRelation, "Attribute"); var pkattribute = CintXML.GetAttribute(xRelation, "PK-Attribute"); var includenull = CintXML.GetBoolAttribute(xRelation, "IncludeNull", false); var entityName = xRelation.ParentNode.Attributes["Entity"].Value; var type = GetAttributeType(attribute, entityName); ConditionExpression cond = new ConditionExpression(); cond.AttributeName = attribute; cond.Operator = Microsoft.Xrm.Sdk.Query.ConditionOperator.In; List <object> ids = new List <object>(); CintDynEntityCollection parentcoll = blocks.ContainsKey(block) ? blocks[block] : null; if (parentcoll != null && parentcoll.Count > 0) { foreach (CintDynEntity parent in parentcoll) { if (string.IsNullOrEmpty(pkattribute)) { if (type == AttributeTypeCode.String) { ids.Add(parent.Id.ToString()); } else { ids.Add(parent.Id); } } else if (type == AttributeTypeCode.String) { ids.Add(parent.Property <EntityReference>(pkattribute, new EntityReference()).Id.ToString()); } else { ids.Add(parent.Property <EntityReference>(pkattribute, new EntityReference()).Id); } } } else { // Adding temp guid to indicate "no matches", as ConditionOperator.In will fail if no values are given ids.Add(new Guid()); } cond.Values.AddRange(ids); if (!includenull) { filter.AddCondition(cond); } else { var orfilter = new FilterExpression(LogicalOperator.Or); orfilter.AddCondition(attribute, Microsoft.Xrm.Sdk.Query.ConditionOperator.Null); orfilter.AddCondition(cond); filter.AddFilter(orfilter); } log.Log("Adding relation condition for {0} in {1} values in {2}.{3}", attribute, ids.Count, block, pkattribute); } log.EndSection(); }
private void ValidatePreReqs(XmlNode xImport, Version thisversion) { log.StartSection("ValidatePreReqs"); XmlNode xPreReqs = CintXML.FindChild(xImport, "PreRequisites"); if (xPreReqs != null) { CintDynEntityCollection cSolutions = GetExistingSolutions(); foreach (XmlNode xPreReq in xPreReqs.ChildNodes) { if (xPreReq.NodeType == XmlNodeType.Element && xPreReq.Name == "Solution") { bool valid = false; string name = CintXML.GetAttribute(xPreReq, "Name"); string comparer = CintXML.GetAttribute(xPreReq, "Comparer"); var version = new Version(); log.Log("Prereq: {0} {1} {2}", name, comparer, version); if (comparer.Contains("this")) { version = thisversion; comparer = comparer.Replace("-this", ""); } else if (comparer != "any") { version = new Version(CintXML.GetAttribute(xPreReq, "Version").Replace('*', '0')); } foreach (CintDynEntity cdSolution in cSolutions) { if (cdSolution.Property("uniquename", "") == name) { log.Log("Found matching solution"); switch (comparer) { case "any": valid = true; break; case "eq": valid = new Version(cdSolution.Property("version", "1.0.0.0")).Equals(version); break; case "ge": valid = new Version(cdSolution.Property("version", "<undefined>")) >= version; break; default: throw new ArgumentOutOfRangeException("Comparer", comparer, "Invalid comparer value"); } } if (valid) { break; } } if (valid) { SendLine("Prerequisite {0} {1} {2} is satisfied", name, comparer, version); } else { SendLine("Prerequisite {0} {1} {2} is NOT satisfied", name, comparer, version); throw new Exception("Prerequisite NOT satisfied (" + name + " " + comparer + " " + version + ")"); } } } } else { log.Log("No prereqs for solution import"); } log.EndSection(); }