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 bool SaveEntity(CintDynEntity cdNewEntity, CintDynEntity cdMatchEntity, bool updateInactiveRecord, bool updateIdentical, int pos, string identifier)
        {
            log.StartSection("SaveEntity " + pos.ToString("000 ") + identifier);
            bool recordSaved = false;

            if (string.IsNullOrWhiteSpace(identifier))
            {
                identifier = cdNewEntity.ToString();
            }
            var newOwner  = cdNewEntity.Property <EntityReference>("ownerid", null);
            var newState  = cdNewEntity.Property <OptionSetValue>("statecode", null);
            var newStatus = cdNewEntity.Property <OptionSetValue>("statuscode", null);
            var newActive = newState != null?CintEntity.GetActiveStates(cdNewEntity.Name).Contains(newState.Value) : true;

            bool 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)
            {
                log.Log("Removing state+status from entity to update");
                cdNewEntity.RemoveProperty("statecode");
                cdNewEntity.RemoveProperty("statuscode");
            }
            if (cdMatchEntity == null)
            {
                cdNewEntity.Create();
                recordSaved = true;
                SendLine("{0:000} Created: {1}", pos, identifier);
            }
            else
            {
                var oldState  = cdMatchEntity.Property <OptionSetValue>("statecode", null);
                var oldActive = oldState != null?CintEntity.GetActiveStates(cdNewEntity.Name).Contains(oldState.Value) : true;

                nowActive      = oldActive;
                cdNewEntity.Id = cdMatchEntity.Id;
                if (!oldActive && (newActive || updateInactiveRecord))
                {   // Inaktiv post som ska aktiveras eller uppdateras
                    cdNewEntity.SetState(0, 1);
                    SendLine("{0:000} Activated: {1} for update", pos, identifier);
                    nowActive = true;
                }

                if (nowActive)
                {
                    var updateattributes = cdNewEntity.Attributes.Keys.ToList();
                    if (updateattributes.Contains(cdNewEntity.PrimaryIdAttribute))
                    {
                        updateattributes.Remove(cdNewEntity.PrimaryIdAttribute);
                    }
                    if (updateIdentical || !EntityAttributesEqual(updateattributes, cdNewEntity, cdMatchEntity))
                    {
                        cdNewEntity.Update();
                        recordSaved = true;
                        SendLine("{0:000} Updated: {1}", pos, identifier);
                    }
                    else
                    {
                        SendLine("{0:000} Skipped: {1} (Identical)", pos, identifier);
                    }
                }
                else
                {
                    SendLine("{0:000} Inactive: {1}", pos, identifier);
                }
                if (newOwner != null && !newOwner.Equals(cdMatchEntity.Property("ownerid", new EntityReference())))
                {
                    cdNewEntity.Assign(newOwner);
                    SendLine("{0:000} Assigned: {1} to {2} {3}", pos, identifier, newOwner.LogicalName, string.IsNullOrEmpty(newOwner.Name) ? newOwner.Id.ToString() : newOwner.Name);
                }
            }
            if (newActive != nowActive)
            {   // Aktiv skall ändras på posten
                var newStatusValue = newStatus.Value;
                if (cdNewEntity.Name == "savedquery" && newState.Value == 1 && newStatusValue == 1)
                {   // Justering för inaktiverad men ej publicerad vy
                    newStatusValue = 2;
                }
                cdNewEntity.SetState(newState.Value, newStatusValue);
                SendLine("{0:000} SetState: {1}: {2}/{3}", pos, identifier, newState.Value, newStatus.Value);
            }
            log.EndSection();
            return(recordSaved);
        }