private void CalculateFromDate <TMessage, TItem>(ref DateTime?fromDate) where TMessage : IDataChangeMessageResponce <TItem> where TItem : IChangedItem { var lastSyncTMessage = SyncAdapterTools.GetLastSendMessage <TMessage>(); if (lastSyncTMessage?.ChangesTo == null) { if (fromDate == null) { LogService.LogWarn( $"{LogWarnMessageHeader} Не задана дата с которой брать изменения и не удалось определить дату из последнего sync-сообщение типа {typeof(TMessage).Name}. Факты-изменения будут обработаны с самого начала!"); } } else { if (fromDate != null) { if (lastSyncTMessage.ChangesTo > fromDate) { LogService.LogWarn( $"{LogWarnMessageHeader} Дата с которой планировалось отправить изменения меньше, чем дата отправки последнего sync-сообщение типа {typeof(TMessage).Name}. Дата начала отправки изменений была изменена с {fromDate.Value:G} на {lastSyncTMessage.ChangesTo.Value:G}"); fromDate = lastSyncTMessage.ChangesTo; } } else { fromDate = lastSyncTMessage.ChangesTo; } } }
private Function GetSyncEntityLimitForDataChangeMessageResponce <TItem>(DateTime?fromDate, DateTime?toDate) where TItem : IChangedItem { var timeFunc = FunctionBuilder.BuildTrue(); if (fromDate != null || toDate != null) { if (fromDate != null && toDate != null) { timeFunc = FunctionBuilder.BuildBetween <SyncDOEntity>(x => x.Date, fromDate, toDate); } else if (fromDate != null) { timeFunc = FunctionBuilder.BuildGreater <SyncDOEntity>(x => x.Date, fromDate); } else { timeFunc = FunctionBuilder.BuildLessOrEqual <SyncDOEntity>(x => x.Date, toDate); } } var typesFunc = FunctionBuilder.BuildTrue(); var supTypes = SyncAdapterTools.GetSupportTypeForChangedItem <TItem>(); if (supTypes.Any()) { typesFunc = FunctionBuilder.BuildIn <SyncDOEntity>(x => x.Setting.Source.Name, supTypes.Select(x => x.FullName)); } return(FunctionBuilder.BuildAnd(FunctionBuilder.BuildIsNotNull <SyncDOEntity>(x => x.Date), timeFunc, typesFunc)); }
/// <inheritdoc /> public virtual void PackChanges <TMessage, TItem>(DateTime?fromDate = null, DateTime?toDate = null) where TMessage : IDataChangeMessageResponce <TItem> where TItem : IChangedItem { //Перевычисляем дату с которой будет собирать изменения, что бы не отправить изменения повторно. CalculateFromDate <TMessage, TItem>(ref fromDate); LogService.LogInfo( $"ChangePackageCollector: Начата обработка фактов-изменений для сообщения типа {typeof(TMessage).Name}{Helper.GetDatePartAsString(fromDate, toDate)}."); try { //Узнаём сколько фактов-изменений было за период с последний отправки изменений. var syncEntityView = SyncDOEntity.Views.E; syncEntityView.AddProperties(Information.ExtractPropertyPath <SyncDOEntity>(x => x.Setting.Source.Name)); var lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(SyncDOEntity), syncEntityView); lcs.ColumnsSort = new[] { new ColumnsSortDef(nameof(SyncDOEntity.Date), SortOrder.Asc) }; lcs.LimitFunction = GetSyncEntityLimitForDataChangeMessageResponce <TItem>(fromDate, toDate); var loadingCount = GetSyncDOEntityCount(lcs); if (loadingCount > 0) { //Определяем размер пакета которым будут отправлены изменения. var packageSize = SyncAdapterTools.GetPackageSizeForMessage <TMessage>(); //Размер порции одной вычитки определяет размерность пакета сообщения. lcs.LoadingBufferSize = packageSize; //Состояние сервиса данных, для порционной вычитки. object state = null; var syncDoEntities = GetSyncDOEntity(lcs, ref state); LogService.LogInfo( $"ChangePackageCollector: Всего фактов-изменений для сообщения типа {typeof(TMessage).Name} - {loadingCount}, размер одного пакета установлен в {packageSize}."); var currentNumPackage = 0; var totalNumPackage = loadingCount / packageSize; //Пока дата сервис возвращает факты-изменения. while (syncDoEntities.Count > 0) { currentNumPackage++; LogService.LogInfo( $"ChangePackageCollector: Обрабатывается {currentNumPackage} порция фактов-изменений из {totalNumPackage}."); var changedItems = new List <TItem>(); //Обрабатываем вычитанную порцию фактов-изменений. foreach (var syncEntity in syncDoEntities) { //Получаем настройки для обработки факта-изменения. GetSyncSettings(syncEntity, out var type, out var mapper, out var appObjPrimaryKey); if (syncEntity.Date != null && syncEntity.AuditChangePK != null) { var appObject = GetDataObjectBySyncEntity(appObjPrimaryKey, type, syncEntity.ObjectStatus, syncEntity.Date.Value); List <string> changedFields = null; if (SyncAdapterTools.GetSendChangedFieldAttributeForMessage <TMessage>()) { changedFields = GetChangedFieldBySyncEntity(syncEntity.ObjectStatus, syncEntity.AuditChangePK.Value); } //маппим объект в xml объект var xmlObjects = GetXMLObjectByMapper(mapper, appObject); //Cкладываем xml-объект в список, который будет передан создателю сообщения об изменении. changedItems.AddRange(xmlObjects.Select(x => CreateChangedItem <TItem>(syncEntity, x, changedFields))); } } //После обработки всех фактов-изменений, создаём сообщение-изменение нужного типа. //Реальный размер объектов-изменения в сообщении может быть больше указанного размера пакета, это происходит из-за преобразований одного объкта в несколько при маппинге. var message = new DataChangesCreator <TMessage, TItem>(changedItems).CreateMessage(); message.Save(); //Вычитываем очередную порцию фактов-изменений. syncDoEntities = GetSyncDOEntity(null, ref state); } LogService.LogInfo( $"ChangePackageCollector: Успешное завершение обработки фактов-изменений для сообщения типа {typeof(TMessage).Name}{Helper.GetDatePartAsString(fromDate, toDate)}."); } else { LogService.LogInfo( $"ChangePackageCollector: Нет новых фактов-изменений для сообщения типа {typeof(TMessage).Name} с изменениями {Helper.GetDatePartAsString(fromDate, toDate)}. Синхронизационные сообщения сформированы не будут!"); } } catch (Exception ex) { LogService.LogError($"{LogErrorMessageHeader} Операция будет прервана!", ex); throw; } }