public virtual async Task CallSyncTo(DtoSetSyncConfig[] toServerDtoSetSyncMaterials, CancellationToken cancellationToken)
        {
            if (toServerDtoSetSyncMaterials.Any())
            {
                using (TDbContext offlineContextForSyncTo = _dbContextProvider())
                {
                    ((IsSyncDbContext)offlineContextForSyncTo).IsSyncDbContext = true;

                    ODataBatch onlineBatchContext = _oDataBatchProvider();

                    foreach (DtoSetSyncConfig toServerSyncConfig in toServerDtoSetSyncMaterials)
                    {
                        IQueryable <ISyncableDto> offlineSet = toServerSyncConfig.OfflineDtoSet(offlineContextForSyncTo);

                        ISyncableDto[] recentlyChangedOfflineDtos = (await offlineSet.IgnoreQueryFilters().Where(s => EF.Property <bool>(s, "IsSynced") == false).AsNoTracking().ToArrayAsync(cancellationToken).ConfigureAwait(false))
                                                                    .Cast <ISyncableDto>()
                                                                    .ToArray();

                        ISyncableDto firstRecentlyChangedOfflineDto = recentlyChangedOfflineDtos.FirstOrDefault();

                        if (firstRecentlyChangedOfflineDto == null)
                        {
                            continue;
                        }

                        TypeInfo dtoType = firstRecentlyChangedOfflineDto.GetType().GetTypeInfo();

                        PropertyInfo[] keyProps = offlineContextForSyncTo
                                                  .Model
                                                  .FindEntityType(dtoType)
                                                  .FindPrimaryKey()
                                                  .Properties
                                                  .Select(x => dtoType.GetProperty(x.Name))
                                                  .ToArray();

                        foreach (ISyncableDto recentlyChangedOfflineDto in recentlyChangedOfflineDtos)
                        {
                            object[] keys = keyProps.Select(p => p.GetValue(recentlyChangedOfflineDto, null)).ToArray();

                            if (recentlyChangedOfflineDto.IsArchived == true)
                            {
                                onlineBatchContext += c => toServerSyncConfig.OnlineDtoSet(c).Key(keys).DeleteEntryAsync();
                            }
                            else if (recentlyChangedOfflineDto.Version == 0)
                            {
                                onlineBatchContext += c => toServerSyncConfig.OnlineDtoSet(c).Set(recentlyChangedOfflineDto).InsertEntryAsync();
                            }
                            else
                            {
                                onlineBatchContext += c => toServerSyncConfig.OnlineDtoSet(c).Key(keys).Set(recentlyChangedOfflineDto).UpdateEntryAsync();
                            }
                        }
                    }

                    await onlineBatchContext.ExecuteAsync(cancellationToken).ConfigureAwait(false);
                }
            }
        }
Beispiel #2
0
        public async Task SyncDtoSets(params string[] dtoSetNames)
        {
            if (dtoSetNames == null)
            {
                throw new ArgumentNullException(nameof(dtoSetNames));
            }

            if (_connectivity.IsConnected == false)
            {
                return;
            }

            DtoSetSyncConfig[] toServerDtoSetSyncMaterials = _configs.Where(c => c.ToServerSync == true && c.ToServerSyncFunc() == true && dtoSetNames.Any(n => n == c.DtoSetName)).ToArray();

            DtoSetSyncConfig[] fromServerDtoSetSyncMaterials = _configs.Where(c => c.FromServerSync == true && c.FromServerSyncFunc() == true && dtoSetNames.Any(n => n == c.DtoSetName)).ToArray();

            if (toServerDtoSetSyncMaterials.Any())
            {
                using (TDbContext offlineContextForSyncTo = _containerProvider.Resolve <TDbContext>())
                {
                    ((IsSyncDbContext)offlineContextForSyncTo).IsSyncDbContext = true;

                    ODataBatch onlineBatchContext = _containerProvider.Resolve <ODataBatch>();

                    foreach (DtoSetSyncConfig toServerSyncConfig in toServerDtoSetSyncMaterials)
                    {
                        IQueryable <ISyncableDto> offlineSet = toServerSyncConfig.OfflineDtoSet(offlineContextForSyncTo);

                        ISyncableDto[] recentlyChangedOfflineDtos = (await offlineSet.IgnoreQueryFilters().Where(s => EF.Property <bool>(s, "IsSynced") == false).AsNoTracking().ToArrayAsync().ConfigureAwait(false))
                                                                    .Cast <ISyncableDto>()
                                                                    .ToArray();

                        ISyncableDto firstRecentlyChangedOfflineDto = recentlyChangedOfflineDtos.FirstOrDefault();

                        if (firstRecentlyChangedOfflineDto == null)
                        {
                            continue;
                        }

                        TypeInfo dtoType = firstRecentlyChangedOfflineDto.GetType().GetTypeInfo();

                        PropertyInfo[] keyProps = offlineContextForSyncTo
                                                  .Model
                                                  .FindEntityType(dtoType)
                                                  .FindPrimaryKey()
                                                  .Properties
                                                  .Select(x => dtoType.GetProperty(x.Name))
                                                  .ToArray();

                        foreach (ISyncableDto recentlyChangedOfflineDto in recentlyChangedOfflineDtos)
                        {
                            object[] keys = keyProps.Select(p => p.GetValue(recentlyChangedOfflineDto, null)).ToArray();

                            if (recentlyChangedOfflineDto.IsArchived == true)
                            {
                                onlineBatchContext += c => toServerSyncConfig.OnlineDtoSet(c).Key(keys).DeleteEntryAsync();
                            }
                            else if (recentlyChangedOfflineDto.Version == 0)
                            {
                                onlineBatchContext += c => toServerSyncConfig.OnlineDtoSet(c).Set(recentlyChangedOfflineDto).InsertEntryAsync();
                            }
                            else
                            {
                                onlineBatchContext += c => toServerSyncConfig.OnlineDtoSet(c).Key(keys).Set(recentlyChangedOfflineDto).UpdateEntryAsync();
                            }
                        }
                    }

                    await onlineBatchContext.ExecuteAsync().ConfigureAwait(false);
                }
            }

            if (fromServerDtoSetSyncMaterials.Any())
            {
                using (TDbContext offlineContextForSyncFrom = _containerProvider.Resolve <TDbContext>())
                {
                    ((IsSyncDbContext)offlineContextForSyncFrom).IsSyncDbContext = true;

                    ODataBatch onlineBatchContext = _containerProvider.Resolve <ODataBatch>();

                    List <DtoSyncConfigSyncFromResults> recentlyChangedOnlineDtos = new List <DtoSyncConfigSyncFromResults>();

                    foreach (DtoSetSyncConfig fromServerSyncConfig in fromServerDtoSetSyncMaterials)
                    {
                        IQueryable <ISyncableDto> offlineSet = fromServerSyncConfig.OfflineDtoSet(offlineContextForSyncFrom);

                        var mostRecentOfflineDto = await offlineSet
                                                   .IgnoreQueryFilters()
                                                   .Select(e => new { e.Version })
                                                   .OrderByDescending(e => e.Version)
                                                   .FirstOrDefaultAsync()
                                                   .ConfigureAwait(false);

                        long maxVersion = mostRecentOfflineDto?.Version ?? 0;

                        onlineBatchContext += async c => recentlyChangedOnlineDtos.Add(new DtoSyncConfigSyncFromResults
                        {
                            DtoSetSyncConfig          = fromServerSyncConfig,
                            RecentlyChangedOnlineDtos = CreateSyncableDtoInstancesFromUnTypedODataResponse(offlineSet.ElementType.GetTypeInfo(), (await(fromServerSyncConfig.OnlineDtoSetForGet ?? fromServerSyncConfig.OnlineDtoSet)(c).Where($"Version gt {maxVersion}").FindEntriesAsync().ConfigureAwait(false)).ToList()),
                            DtoType             = offlineSet.ElementType.GetTypeInfo(),
                            HadOfflineDtoBefore = mostRecentOfflineDto != null
                        });
                    }

                    await onlineBatchContext.ExecuteAsync().ConfigureAwait(false);

                    foreach (DtoSyncConfigSyncFromResults result in recentlyChangedOnlineDtos.Where(r => r.RecentlyChangedOnlineDtos.Any()))
                    {
                        if (result.HadOfflineDtoBefore == false)
                        {
                            await offlineContextForSyncFrom.AddRangeAsync(result.RecentlyChangedOnlineDtos).ConfigureAwait(false);

                            foreach (ISyncableDto r in result.RecentlyChangedOnlineDtos)
                            {
                                offlineContextForSyncFrom.Entry(r).Property("IsSynced").CurrentValue = true;
                            }
                        }
                        else
                        {
                            PropertyInfo[] keyProps = offlineContextForSyncFrom
                                                      .Model
                                                      .FindEntityType(result.DtoType)
                                                      .FindPrimaryKey()
                                                      .Properties.Select(x => result.DtoType.GetProperty(x.Name))
                                                      .ToArray();

                            IQueryable <ISyncableDto> offlineSet = result.DtoSetSyncConfig.OfflineDtoSet(offlineContextForSyncFrom);

                            string        equivalentOfflineDtosQuery  = "";
                            List <object> equivalentOfflineDtosParams = new List <object>();
                            int           parameterIndex = 0;

                            equivalentOfflineDtosQuery = string.Join(" || ", result.RecentlyChangedOnlineDtos.Select(s =>
                            {
                                return($" ( {string.Join(" && ", keyProps.Select(k => { equivalentOfflineDtosParams.Add(k.GetValue(s)); return $"{k.Name} == @{parameterIndex++}"; }))} )");
                            }));

                            List <ISyncableDto> equivalentOfflineDtos = await offlineSet.Where(equivalentOfflineDtosQuery, equivalentOfflineDtosParams.ToArray()).IgnoreQueryFilters().ToListAsync().ConfigureAwait(false);

                            foreach (ISyncableDto recentlyChangedOnlineDto in result.RecentlyChangedOnlineDtos)
                            {
                                bool hasEquivalentInOfflineDb = equivalentOfflineDtos.Any(d => keyProps.All(k => k.GetValue(d).Equals(k.GetValue(recentlyChangedOnlineDto))));

                                if (recentlyChangedOnlineDto.IsArchived == false || hasEquivalentInOfflineDb == true)
                                {
                                    if (recentlyChangedOnlineDto.IsArchived == true)
                                    {
                                        offlineContextForSyncFrom.Remove(recentlyChangedOnlineDto);
                                    }
                                    else if (hasEquivalentInOfflineDb == true)
                                    {
                                        offlineContextForSyncFrom.Update(recentlyChangedOnlineDto);
                                        offlineContextForSyncFrom.Entry(recentlyChangedOnlineDto).Property("IsSynced").CurrentValue = true;
                                    }
                                    else
                                    {
                                        await offlineContextForSyncFrom.AddAsync(recentlyChangedOnlineDto).ConfigureAwait(false);

                                        offlineContextForSyncFrom.Entry(recentlyChangedOnlineDto).Property("IsSynced").CurrentValue = true;
                                    }
                                }
                            }
                        }
                    }

                    await offlineContextForSyncFrom.SaveChangesAsync().ConfigureAwait(false);
                }
            }
        }