/// <summary> /// Attach a master /// </summary> public object Add(Type scopingType, object scopingKey, object item) { var dataManager = MdmDataManagerFactory.GetDataManager(scopingType); if (dataManager == null) { throw new NotSupportedException($"MDM is not configured for {scopingType}"); } // Detach if (scopingKey is Guid scopedKey && item is IdentifiedDataReference childObject) { try { var transaction = new Bundle(dataManager.MdmTxMasterLink(scopedKey, childObject.Key.Value, new IdentifiedData[0], true)); var retVal = this.m_batchService.Insert(transaction, TransactionMode.Commit, AuthenticationContext.Current.Principal); return(retVal); } catch (Exception e) { this.m_tracer.TraceError("Error attaching master- {0}", e); throw new MdmException($"Error detaching {scopingKey} from {childObject.Key}", e); } }
/// <summary> /// Search for the specified entity /// </summary> public IEnumerable <TEntity> Search <TEntity>(string[] term, Guid queryId, int offset, int?count, out int totalResults, ModelSort <TEntity>[] orderBy) where TEntity : IdentifiedData, new() { var searchTerm = String.Join(" and ", term); // Perform the queries on the terms if (this.m_configuration.ResourceTypes.Any(rt => rt.Type == typeof(TEntity))) // Under MDM control { var principal = AuthenticationContext.Current.Principal; // HACK: Change this method to detect the type var idps = ApplicationServiceContext.Current.GetService <IDataPersistenceService <Entity> >(); if (idps == null) { throw new InvalidOperationException("Cannot find a query repository service"); } var expression = QueryExpressionParser.BuildLinqExpression <Entity>(new NameValueCollection() { { "classConcept", MdmConstants.MasterRecordClassification.ToString() }, { "relationship[97730a52-7e30-4dcd-94cd-fd532d111578].source.id", $":(freetext|{searchTerm})" } }); var results = idps.Query(expression, offset, count, out totalResults, principal); var mdmDataManager = MdmDataManagerFactory.GetDataManager <TEntity>(); if (Environment.ProcessorCount > 4) { return(results.AsParallel().AsOrdered().Select(o => mdmDataManager.CreateMasterContainerForMasterEntity(o).Synthesize(principal)).OfType <TEntity>().ToList()); } else { return(results.Select(o => mdmDataManager.CreateMasterContainerForMasterEntity(o).Synthesize(principal)).OfType <TEntity>().ToList()); } } else { // Does the provider support freetext search clauses? var idps = ApplicationServiceContext.Current.GetService <IDataPersistenceService <TEntity> >(); if (idps == null) { throw new InvalidOperationException("Cannot find a query repository service"); } return(idps.Query(o => o.FreetextSearch(searchTerm), offset, count, out totalResults, AuthenticationContext.Current.Principal, orderBy)); } }
/// <summary> /// Perform the operation /// </summary> public override object Invoke(Type scopingType, object scopingKey, ParameterCollection parameters) { var dataManager = MdmDataManagerFactory.GetDataManager(scopingType); if (dataManager == null) { throw new NotSupportedException($"MDM is not configured for {scopingType}"); } if (scopingKey == null) { parameters.TryGet <bool>("clear", out bool clear); this.m_jobManager.StartJob(typeof(MdmMatchJob <>).MakeGenericType(scopingType), new object[] { clear }); return(null); } else if (scopingKey is Guid scopingObjectKey) { // Load the current master from @scopingKey if (!dataManager.IsMaster(scopingObjectKey)) { throw new KeyNotFoundException($"{scopingObjectKey} is not an MDM Master"); } // Now - we want to prepare a transaction Bundle retVal = new Bundle(); if (parameters.TryGet <bool>("clear", out bool clear) && clear) { foreach (var itm in dataManager.GetCandidateLocals(scopingObjectKey).Where(o => o.ClassificationKey == MdmConstants.AutomagicClassification)) { if (itm is EntityRelationship er) { er.BatchOperation = Core.Model.DataTypes.BatchOperationType.Delete; retVal.Add(er); } else if (itm is ActRelationship ar) { ar.BatchOperation = Core.Model.DataTypes.BatchOperationType.Delete; retVal.Add(ar); } } } retVal.AddRange(dataManager.MdmTxDetectCandidates(dataManager.MdmGet(scopingObjectKey).Synthesize(AuthenticationContext.Current.Principal) as Entity, retVal.Item)); // Now we want to save? try { retVal = this.m_batchService.Insert(retVal, TransactionMode.Commit, AuthenticationContext.Current.Principal); } catch (Exception e) { this.m_tracer.TraceError("Error persisting re-match: {0}", e.Message); throw new MdmException("Error persisting re-match operation", e); } return(retVal); } else { throw new InvalidOperationException("Cannot determine the operation"); } }
/// <summary> /// Start the daemon /// </summary> public bool Start() { this.Starting?.Invoke(this, EventArgs.Empty); // Pre-register types for serialization foreach (var itm in this.m_configuration.ResourceTypes) { if (itm.Type == typeof(Entity)) { throw new InvalidOperationException("Cannot bind MDM control to Entity or Act , only sub-classes"); } var rt = itm.Type; string typeName = $"{rt.Name}Master"; if (typeof(Entity).IsAssignableFrom(rt)) { rt = typeof(EntityMaster <>).MakeGenericType(rt); } else if (typeof(Act).IsAssignableFrom(rt)) { rt = typeof(ActMaster <>).MakeGenericType(rt); } ModelSerializationBinder.RegisterModelType(typeName, rt); } // Wait until application context is started ApplicationServiceContext.Current.Started += (o, e) => { if (this.m_matchingService == null) { this.m_traceSource.TraceWarning("The MDM Service should be using a record matching service"); } // Replace matching var mdmMatcher = this.m_serviceManager.CreateInjected <MdmRecordMatchingService>(); this.m_serviceManager.AddServiceProvider(mdmMatcher); var mdmMatchConfig = this.m_serviceManager.CreateInjected <MdmMatchConfigurationService>(); this.m_serviceManager.AddServiceProvider(mdmMatchConfig); if (this.m_matchingService != null) { this.m_serviceManager.RemoveServiceProvider(this.m_matchingService.GetType()); } if (this.m_matchConfigurationService != null) { this.m_serviceManager.RemoveServiceProvider(this.m_matchConfigurationService.GetType()); } foreach (var itm in this.m_configuration.ResourceTypes) { this.m_traceSource.TraceInfo("Adding MDM listener for {0}...", itm.Type.Name); MdmDataManagerFactory.RegisterDataManager(itm.Type); var idt = typeof(MdmResourceHandler <>).MakeGenericType(itm.Type); var ids = this.m_serviceManager.CreateInjected(idt) as IDisposable; this.m_listeners.Add(ids); this.m_serviceManager.AddServiceProvider(ids); this.m_serviceManager.AddServiceProvider(MdmDataManagerFactory.CreateMerger(itm.Type)); // Add job var jobType = typeof(MdmMatchJob <>).MakeGenericType(itm.Type); var job = this.m_serviceManager.CreateInjected(jobType) as IJob; this.m_jobManager?.AddJob(job, JobStartType.Never); } // Add an entity relationship and act relationship watcher to the persistence layer for after update // this will ensure that appropriate cleanup is performed on successful processing of data this.m_entityRelationshipService = ApplicationServiceContext.Current.GetService <IDataPersistenceService <EntityRelationship> >(); this.m_entityService = ApplicationServiceContext.Current.GetService <IDataPersistenceService <Entity> >(); ApplicationServiceContext.Current.GetService <IDataPersistenceService <Bundle> >().Inserted += RecheckBundleTrigger; ApplicationServiceContext.Current.GetService <IDataPersistenceService <Bundle> >().Updated += RecheckBundleTrigger; ApplicationServiceContext.Current.GetService <IDataPersistenceService <Bundle> >().Obsoleted += RecheckBundleTrigger; this.m_entityRelationshipService.Inserted += RecheckRelationshipTrigger; this.m_entityRelationshipService.Updated += RecheckRelationshipTrigger; this.m_entityRelationshipService.Obsoleted += RecheckRelationshipTrigger; // Add an MDM listener for subscriptions if (this.m_subscriptionExecutor != null) { m_subscriptionExecutor.Executing += MdmSubscriptionExecuting; m_subscriptionExecutor.Executed += MdmSubscriptionExecuted; } this.m_listeners.Add(new BundleResourceInterceptor(this.m_listeners)); // Slipstream the MdmEntityProvider //EntitySource.Current = new EntitySource(new MdmEntityProvider()); // HACK: Replace any freetext service with our own this.m_serviceManager.RemoveServiceProvider(typeof(IFreetextSearchService)); m_serviceManager.AddServiceProvider(new MdmFreetextSearchService()); }; this.Started?.Invoke(this, EventArgs.Empty); return(true); }