/// <summary> /// Enrich the registration event /// </summary> internal void EnrichRegistrationEvent(IDbConnection conn, IDbTransaction tx, RegistrationEvent hsrEvent) { decimal tryDec; ISystemConfigurationService configService = ApplicationContext.ConfigurationService; // Create a query based on the person Person subject = hsrEvent.FindComponent(HealthServiceRecordSiteRoleType.SubjectOf) as Person; if (subject.AlternateIdentifiers.Exists(o => o.Domain == configService.OidRegistrar.GetOid(ClientRegistryOids.CLIENT_CRID).Oid)) { subject = new Person() { AlternateIdentifiers = new List <DomainIdentifier>(subject.AlternateIdentifiers.FindAll(o => o.Domain == configService.OidRegistrar.GetOid(ClientRegistryOids.CLIENT_CRID).Oid)), Status = StatusType.Normal } } ; else if (subject.AlternateIdentifiers.Exists(o => o is AuthorityAssignedDomainIdentifier)) { subject = new Person() { AlternateIdentifiers = new List <DomainIdentifier>(subject.AlternateIdentifiers.FindAll(o => o is AuthorityAssignedDomainIdentifier)), Status = StatusType.Normal } } ; else { subject = new Person() { AlternateIdentifiers = new List <DomainIdentifier>(subject.AlternateIdentifiers), Status = StatusType.Normal } }; QueryEvent query = new QueryEvent(); RegistrationEvent evt = new RegistrationEvent(); query.Add(evt, "SUBJ", HealthServiceRecordSiteRoleType.SubjectOf, null); evt.Status = StatusType.Active | StatusType.Obsolete; evt.Add(subject, "SUBJ", HealthServiceRecordSiteRoleType.SubjectOf, null); query.Add(new QueryParameters() { MatchingAlgorithm = MatchAlgorithm.Exact, MatchStrength = MatchStrength.Exact }, "FLTR", HealthServiceRecordSiteRoleType.FilterOf, null); var tRecordIds = QueryRecord(query); if (tRecordIds.Length != 1) { throw new MissingPrimaryKeyException(ApplicationContext.LocaleService.GetString("DBCF004")); } else if (tRecordIds[0].Domain != configService.OidRegistrar.GetOid(ClientRegistryOids.REGISTRATION_EVENT).Oid) { throw new MissingPrimaryKeyException(ApplicationContext.LocaleService.GetString("DBCF005")); } tryDec = Decimal.Parse(tRecordIds[0].Identifier); hsrEvent.AlternateIdentifier = tRecordIds[0]; }
/// <summary> /// Find conflicts using identifiers /// </summary> public IEnumerable <SVC.Core.DataTypes.VersionedDomainIdentifier> FindIdConflicts(RegistrationEvent registration) { var registrationService = this.Context.GetService(typeof(IDataRegistrationService)) as IDataRegistrationService; VersionedDomainIdentifier[] pid = null; // Check if the person exists just via the identifier? // This is important because it is not necessarily a merge but an "update if exists" var subject = registration.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf) as Person; QueryParameters qp = new QueryParameters() { Confidence = 1.0f, MatchingAlgorithm = MatchAlgorithm.Exact, MatchStrength = MatchStrength.Exact }; var config = this.Context.GetService(typeof(ISystemConfigurationService)) as ISystemConfigurationService; List <VersionedDomainIdentifier> conflictIds = new List <VersionedDomainIdentifier>(); foreach (var id in subject.AlternateIdentifiers) { var data = config.OidRegistrar.FindData(id.Domain); if (data == null || !data.Attributes.Exists(a => a.Key == "IsUniqueIdentifier" && Convert.ToBoolean(a.Value))) { continue; } var patientQuery = new QueryEvent(); var registrationEvent = new RegistrationEvent(); patientQuery.Add(registrationEvent, "SUBJ", HealthServiceRecordSiteRoleType.SubjectOf, null); patientQuery.Add(qp, "FLT", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.FilterOf, null); registrationEvent.Add(new Person() { AlternateIdentifiers = new List <DomainIdentifier>() { id } }, "SUBJ", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf, null); // Perform the query pid = registrationService.QueryRecord(patientQuery); foreach (var result in pid) { if (!conflictIds.Exists(o => o.Identifier.ToString() == result.Identifier)) { conflictIds.Add(result); } } } return(conflictIds.ToArray()); }
/// <summary> /// Find conflicts using fuzzy match /// </summary> public IEnumerable <VersionedDomainIdentifier> FindFuzzyConflicts(RegistrationEvent registration) { var registrationService = this.Context.GetService(typeof(IDataRegistrationService)) as IDataRegistrationService; var persistenceService = this.Context.GetService(typeof(IDataPersistenceService)) as IDataPersistenceService; var clientRegistryConfigService = this.Context.GetService(typeof(IClientRegistryConfigurationService)) as IClientRegistryConfigurationService; VersionedDomainIdentifier[] pid = null; var subject = registration.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf) as Person; QueryParameters qp = new QueryParameters() { Confidence = 1.0f, MatchingAlgorithm = MatchAlgorithm.Exact, MatchStrength = MatchStrength.Exact }; if (subject.Status != StatusType.Active) { return(pid); } var patientQuery = new QueryEvent(); var registrationEvent = new RegistrationEvent(); patientQuery.Add(registrationEvent, "SUBJ", HealthServiceRecordSiteRoleType.SubjectOf, null); patientQuery.Add(qp, "FLT", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.FilterOf, null); // Create merge filter for fuzzy match var ssubject = clientRegistryConfigService.CreateMergeFilter(subject); if (ssubject != null) // Minimum criteria was met { registrationEvent.Add(ssubject, "SUBJ", HealthServiceRecordSiteRoleType.SubjectOf, null); pid = registrationService.QueryRecord(patientQuery); } else { pid = new VersionedDomainIdentifier[0]; } // Now, look for all with an assigning authority if (pid.Length > 0) { pid = pid.Where(o => !(o.Identifier == registration.Id.ToString() && o.Domain == ApplicationContext.ConfigurationService.OidRegistrar.GetOid(ClientRegistryOids.REGISTRATION_EVENT).Oid)).ToArray(); // Load each match quickly and ensure that they don't already have a // different identifier from an assigning authority (not CR_CID) provided // in the registration method. For example, if John Smith, Male, 1984-05-22, 123 Main Street West is // registered from system X with ID 102 , and a subsequent registration message for John Smith, Male, 1984-05-22, 123 Main Street West // is received from system X with ID 104, it is pretty much assured they aren't the same person. If however the // latter message came from system Y with ID 104, then the two should be considered a match. ssubject.AlternateIdentifiers = new List <DomainIdentifier>(); List <VersionedDomainIdentifier> exclude = new List <VersionedDomainIdentifier>(); foreach (var altId in subject.AlternateIdentifiers) { if (altId.Domain != ApplicationContext.ConfigurationService.OidRegistrar.GetOid(ClientRegistryOids.CLIENT_CRID).Oid) { var oidData = ApplicationContext.ConfigurationService.OidRegistrar.FindData(altId.Domain); if (oidData == null || oidData.Attributes.Find(o => o.Key == "IsUniqueIdentifier").Value == null || Boolean.Parse(oidData.Attributes.Find(o => o.Key == "IsUniqueIdentifier").Value)) { ssubject.AlternateIdentifiers.Add(new DomainIdentifier() { Domain = altId.Domain }); } } } foreach (var p in pid) { var re = persistenceService.GetContainer(p, true) as RegistrationEvent; var pat = re.FindComponent(HealthServiceRecordSiteRoleType.SubjectOf) as Person; if (pat.Id == subject.Id || pat.Status != StatusType.Active) // same person { exclude.Add(re.AlternateIdentifier); } else if (pat.AlternateIdentifiers.Exists(o => ssubject.AlternateIdentifiers.Exists(r => r.Domain == o.Domain))) { exclude.Add(re.AlternateIdentifier); } } pid = pid.Where(o => !exclude.Exists(i => i.Domain == o.Domain && i.Identifier == o.Identifier)).ToArray(); } return(pid); }
/// <summary> /// Notify the operation /// </summary> public void Notify(NotificationQueueWorkItem workItem) { // configuration service ISystemConfigurationService config = this.Context.GetService(typeof(ISystemConfigurationService)) as ISystemConfigurationService; ILocalizationService locale = this.Context.GetService(typeof(ILocalizationService)) as ILocalizationService; // Common message bits we need to update IMessage notificationMessage = null; MSH msh = null; PID pid = null; EVN evn = null; PV1 pv1 = null; MRG mrg = null; // Identify the work item action switch (workItem.Action) { case MARC.HI.EHRS.CR.Notification.PixPdq.Configuration.ActionType.Create: { ADT_A01 message = new ADT_A01(); msh = message.MSH; pid = message.PID; evn = message.EVN; pv1 = message.PV1; notificationMessage = message; msh.MessageType.TriggerEvent.Value = "A04"; break; } case MARC.HI.EHRS.CR.Notification.PixPdq.Configuration.ActionType.DuplicatesResolved: { ADT_A39 message = new ADT_A39(); msh = message.MSH; msh.MessageType.TriggerEvent.Value = "A40"; pid = message.GetPATIENT(0).PID; evn = message.EVN; pv1 = message.GetPATIENT(0).PV1; mrg = message.GetPATIENT(0).MRG; notificationMessage = message; break; }; case MARC.HI.EHRS.CR.Notification.PixPdq.Configuration.ActionType.Update: { ADT_A01 message = new ADT_A01(); msh = message.MSH; pid = message.PID; evn = message.EVN; pv1 = message.PV1; notificationMessage = message; msh.MessageType.TriggerEvent.Value = "A08"; break; } } // Populate the MSH header first this.UpdateMSH(msh, config); // Populate the EVN segment evn.EventTypeCode.Value = workItem.Event.Mode.ToString(); evn.RecordedDateTime.TimeOfAnEvent.Value = (TS)workItem.Event.Timestamp; // Populate the PID segment Person subject = workItem.Event.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf) as Person; this.UpdatePID(subject, pid, config); pv1.PatientClass.Value = "I"; // Populate MRG if (mrg != null) { var registration = this.Context.GetService(typeof(IDataRegistrationService)) as IDataRegistrationService; var persistence = this.Context.GetService(typeof(IDataPersistenceService)) as IDataPersistenceService; var replacements = subject.FindAllComponents(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.ReplacementOf); foreach (PersonRegistrationRef rplc in replacements) { // First, need to de-persist the identifiers QueryParameters qp = new QueryParameters() { Confidence = 1.0f, MatchingAlgorithm = MatchAlgorithm.Exact, MatchStrength = MatchStrength.Exact }; var queryEvent = new QueryEvent(); var patientQuery = new RegistrationEvent(); queryEvent.Add(qp, "FLT", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.FilterOf, null); patientQuery.Add(new Person() { AlternateIdentifiers = rplc.AlternateIdentifiers }, "SUBJ", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf, null); queryEvent.Add(patientQuery, "SUBJ", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf, null); // Perform the query var patientIdentifiers = registration.QueryRecord(queryEvent); if (patientIdentifiers.Length == 0) { throw new InvalidOperationException(); } var replacedPerson = (persistence.GetContainer(patientIdentifiers[0], true) as RegistrationEvent).FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf) as Person; foreach (var ii in replacedPerson.AlternateIdentifiers.FindAll(o => this.Target.NotificationDomain.Exists(d => d.Domain == o.Domain))) { var cx = mrg.GetPriorPatientIdentifierList(mrg.PriorAlternatePatientIDRepetitionsUsed); cx.ID.Value = ii.Identifier; if (String.IsNullOrEmpty(ii.AssigningAuthority)) { cx.AssigningAuthority.NamespaceID.Value = config.OidRegistrar.FindData(ii.Domain).Attributes.Find(o => o.Key == "AssigningAuthorityName").Value; } else { cx.AssigningAuthority.NamespaceID.Value = ii.AssigningAuthority; } cx.AssigningAuthority.UniversalID.Value = ii.Domain; cx.AssigningAuthority.UniversalIDType.Value = "ISO"; } } } // Send var queueItem = new Hl7MessageQueue.MessageQueueWorkItem(this.Target, notificationMessage); if (!queueItem.TrySend()) { Trace.TraceWarning(locale.GetString("NTFW005")); Hl7MessageQueue.Current.EnqueueMessageItem(queueItem); } }
/// <summary> /// Get recent activity /// </summary> public RegistrationEventCollection GetRecentActivity(TimestampSet timeRange, int offset, int count, bool identifierOnly) { // Get all Services IAuditorService auditSvc = ApplicationContext.CurrentContext.GetService(typeof(IAuditorService)) as IAuditorService; IDataRegistrationService regSvc = ApplicationContext.CurrentContext.GetService(typeof(IDataRegistrationService)) as IDataRegistrationService; IDataPersistenceService repSvc = ApplicationContext.CurrentContext.GetService(typeof(IDataPersistenceService)) as IDataPersistenceService; // Audit message AuditData audit = this.ConstructAuditData(ActionType.Read, EventIdentifierType.Export); audit.EventTypeCode = new CodeValue("ADM_GetRegistrations"); try { // Result identifiers VersionedDomainIdentifier[] vids = null; var dummyQuery = new QueryEvent(); dummyQuery.Add(new RegistrationEvent() { EventClassifier = RegistrationEventType.Register, EffectiveTime = timeRange }, "SUBJ", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf, null); vids = regSvc.QueryRecord(dummyQuery); RegistrationEventCollection retVal = new RegistrationEventCollection(); Object syncLock = new object(); retVal.Count = vids.Length; // Now fetch each one asynchronously if (!identifierOnly) { using (WaitThreadPool thdPool = new WaitThreadPool(Environment.ProcessorCount * 2)) { foreach (var id in vids.Skip(offset).Take(count)) { thdPool.QueueUserWorkItem( delegate(object state) { try { var itm = repSvc.GetContainer(state as VersionedDomainIdentifier, true); lock (syncLock) retVal.Event.Add(itm as RegistrationEvent); } catch (Exception e) { Trace.TraceError("Could not fetch result {0} : {1}", (state as VersionedDomainIdentifier).Identifier, e.ToString()); } } , id); } // Wait until fetch is done thdPool.WaitOne(new TimeSpan(0, 0, 30), false); } //retVal.Event.Sort((a, b) => b.Timestamp.CompareTo(a.Timestamp)); // Add audit data foreach (var res in retVal.Event) { audit.AuditableObjects.Add(new AuditableObject() { IDTypeCode = AuditableObjectIdType.ReportNumber, LifecycleType = AuditableObjectLifecycle.Export, ObjectId = String.Format("{0}^^^&{1}&ISO", res.AlternateIdentifier.Identifier, res.AlternateIdentifier.Domain), Role = AuditableObjectRole.MasterFile, Type = AuditableObjectType.SystemObject, QueryData = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("loadFast=true")) }); } } return(retVal); } catch (Exception e) { Trace.TraceError("Could not execute GetRegistrations : {0}", e.ToString()); audit.Outcome = OutcomeIndicator.EpicFail; #if DEBUG throw new FaultException(new FaultReason(e.ToString()), new FaultCode(e.GetType().Name)); #else throw new FaultException(new FaultReason(e.Message), new FaultCode(e.GetType().Name)); #endif } finally { if (auditSvc != null) { auditSvc.SendAudit(audit); } } }
/// <summary> /// Create a patient registry duplicates resolved message /// </summary> private Everest.Interfaces.IInteraction CreatePatientRegistryDuplicatesResolvedMessage(Core.ComponentModel.RegistrationEvent registrationEvent, TargetConfiguration configuration) { // Construct the return value PRPA_IN201304UV02 retVal = new PRPA_IN201304UV02( Guid.NewGuid(), DateTime.Now, PRPA_IN201304UV02.GetInteractionId(), ProcessingID.Production, "T", AcknowledgementCondition.Always); // Construct the sending node retVal.VersionCode = HL7StandardVersionCode.Version3_Prerelease1; retVal.Sender = CreateSenderNode(); retVal.Receiver.Add(CreateReceiverNode(configuration)); // Construct the control act process retVal.controlActProcess = new Everest.RMIM.UV.NE2008.MFMI_MT700701UV01.ControlActProcess <Everest.RMIM.UV.NE2008.PRPA_MT201303UV02.Patient, object>("EVN"); // Get the subjects and components var subject = registrationEvent.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf) as Person; var providerOrg = subject.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.PlaceOfEntry | SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.InformantTo) as HealthcareParticipant; var custodian = registrationEvent.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.PlaceOfRecord | SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.ResponsibleFor); var replacements = subject.FindAllComponents(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.ReplacementOf); // Create the person List <DomainIdentifier> identifiers = new List <DomainIdentifier>(subject.AlternateIdentifiers.FindAll(o => configuration.NotificationDomain.Exists(d => d.Domain.Equals(o.Domain)))); var eventRegistration = new Everest.RMIM.UV.NE2008.MFMI_MT700701UV01.Subject1 <Everest.RMIM.UV.NE2008.PRPA_MT201303UV02.Patient, object>(false, new Everest.RMIM.UV.NE2008.MFMI_MT700701UV01.RegistrationEvent <Everest.RMIM.UV.NE2008.PRPA_MT201303UV02.Patient, object>( ActStatus.Active, new Everest.RMIM.UV.NE2008.MFMI_MT700701UV01.Subject2 <Everest.RMIM.UV.NE2008.PRPA_MT201303UV02.Patient>( new Everest.RMIM.UV.NE2008.PRPA_MT201303UV02.Patient( CreateIISet(identifiers), RoleStatus.Active, CreatePerson(subject, new TargetConfiguration(String.Empty, null, configuration.Notifier.GetType().Name, null)), providerOrg == null ? null : CreateProviderOrganization(providerOrg) ) ) ) ); // Get person data var personData = eventRegistration.RegistrationEvent.Subject1.registeredRole.PatientEntityChoiceSubject as Everest.RMIM.UV.NE2008.PRPA_MT201303UV02.Person; personData.AsOtherIDs.Clear(); retVal.controlActProcess.Subject.Add(eventRegistration); // TODO: Replacement of compatibility mode for other XDS registries // Replacement var registration = this.Context.GetService(typeof(IDataRegistrationService)) as IDataRegistrationService; var persistence = this.Context.GetService(typeof(IDataPersistenceService)) as IDataPersistenceService; foreach (PersonRegistrationRef rplc in replacements) { // First, need to de-persist the identifiers QueryParameters qp = new QueryParameters() { Confidence = 1.0f, MatchingAlgorithm = MatchAlgorithm.Exact, MatchStrength = MatchStrength.Exact }; var patientQuery = new QueryEvent(); RegistrationEvent regEvent = new RegistrationEvent() { }; patientQuery.Add(regEvent, "SUBJ", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf, null); patientQuery.Add(qp, "FLT", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.FilterOf, null); regEvent.Add(new Person() { AlternateIdentifiers = rplc.AlternateIdentifiers }, "SUBJ", SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf, null); // Perform the query var pid = registration.QueryRecord(patientQuery); if (pid.Length == 0) { throw new InvalidOperationException(); } var replacedPerson = (persistence.GetContainer(pid[0], true) as RegistrationEvent).FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf) as Person; var ids = CreateIISet(replacedPerson.AlternateIdentifiers.FindAll(o => configuration.NotificationDomain.Exists(d => d.Domain == o.Domain))); if (ids.Count == 0) { ; // TODO: Trace log } else { eventRegistration.RegistrationEvent.ReplacementOf.Add(new Everest.RMIM.UV.NE2008.MFMI_MT700701UV01.ReplacementOf( new Everest.RMIM.UV.NE2008.MFMI_MT700701UV01.PriorRegistration( null, ActStatus.Obsolete, new Everest.RMIM.UV.NE2008.MFMI_MT700701UV01.Subject3( new Everest.RMIM.UV.NE2008.MFMI_MT700701UV01.PriorRegisteredRole( ids ) ), null ) )); } } if (eventRegistration.RegistrationEvent.ReplacementOf.Count == 0) { throw new InvalidOperationException("Nothing to do"); } // Custodian? eventRegistration.RegistrationEvent.Custodian = CreateCustodian(registrationEvent, configuration); return(retVal); }
/// <summary> /// Store a container /// </summary> public VersionedDomainIdentifier StoreContainer(System.ComponentModel.IContainer storageData, DataPersistenceMode mode) { if (m_disposed) { throw new ObjectDisposedException("DatabasePersistenceService"); } // Merge IEnumerable <VersionedDomainIdentifier> pid = null; var regEvent = storageData as RegistrationEvent; if (this.m_clientRegistryMerge != null && regEvent != null) { bool fuzzy = false; pid = this.m_clientRegistryMerge.FindIdConflicts(regEvent); // Do we have a match? if (pid.Count() == 0) // if we didn't find any id conflicts go to fuzzy mode { if (this.m_clientRegistryConfiguration.Configuration.Registration.AutoMerge) // we have to do this now :( { fuzzy = true; pid = this.m_clientRegistryMerge.FindFuzzyConflicts(regEvent); if (pid.Count() == 1) { regEvent.AlternateIdentifier = pid.First(); Trace.TraceInformation("Matched with {0} records (fuzzy={1}, autoOn={2}, updateEx={3})", pid.Count(), fuzzy, this.m_clientRegistryConfiguration.Configuration.Registration.AutoMerge, this.m_clientRegistryConfiguration.Configuration.Registration.UpdateIfExists); return(this.UpdateContainer(regEvent, mode)); } } } else if (this.m_clientRegistryConfiguration.Configuration.Registration.UpdateIfExists) { // Update if (pid.Count() == 1) { Trace.TraceInformation("Updating record {0} because it matched by identifier", regEvent.Id); regEvent.AlternateIdentifier = pid.First(); return(this.UpdateContainer(regEvent, mode)); } } } else { pid = new List <VersionedDomainIdentifier>(); } //// do a sanity check, have we already persisted this record? if (!ValidationSettings.AllowDuplicateRecords) { var duplicateQuery = new QueryEvent(); duplicateQuery.Add((storageData as ICloneable).Clone() as HealthServiceRecordContainer, "SUBJ", HealthServiceRecordSiteRoleType.SubjectOf, null); duplicateQuery.Add(new QueryParameters() { MatchStrength = Core.ComponentModel.MatchStrength.Exact, MatchingAlgorithm = MatchAlgorithm.Exact }, "FLT", HealthServiceRecordSiteRoleType.FilterOf, null); var storedRecords = QueryRecord(duplicateQuery as IComponent); if (storedRecords.Length != 0) { throw new DuplicateNameException(ApplicationContext.LocaleService.GetString("DTPE004")); } } // Get the persister IComponentPersister persister = GetPersister(storageData.GetType()); if (persister != null) { IDbTransaction tx = null; IDbConnection conn = null; try { conn = DatabasePersistenceService.ConnectionManager.GetConnection(); tx = conn.BeginTransaction(); var retVal = persister.Persist(conn, tx, storageData as IComponent, false); // Set the mode if (m_configuration.OverridePersistenceMode.HasValue) { mode = m_configuration.OverridePersistenceMode.Value; } // Commit or rollback if (mode == DataPersistenceMode.Production) { tx.Commit(); tx = null; // Notify that reconciliation is required and mark merge candidates if (pid.Count() > 0) { this.m_clientRegistryMerge.MarkConflicts(retVal, pid); if (this.m_notificationService != null && pid.Count() != 0) { var list = new List <VersionedDomainIdentifier>(pid) { retVal }; this.m_notificationService.NotifyReconciliationRequired(list); } } else if (this.m_clientRegistryMerge != null) { this.m_threadPool.QueueUserWorkItem(this.MarkConflictsAsync, retVal); } // Notify register if (this.m_notificationService != null && storageData is RegistrationEvent) { this.m_notificationService.NotifyRegister(storageData as RegistrationEvent); } } else { tx.Rollback(); } return(retVal); } catch (Exception e) { if (tx != null) { tx.Rollback(); } throw; } finally { if (tx != null) { tx.Dispose(); } if (conn != null) { DatabasePersistenceService.ConnectionManager.ReleaseConnection(conn); conn = null; } } } else { Trace.TraceError("Can't find a persistence handler for type '{0}'", storageData.GetType().Name); throw new DataException(String.Format("Can't persist type '{0}'", storageData.GetType().Name)); } }