Example #1
0
        public static bool ValidateDuplicated <TModel, TIdentity>(this ImportMethod method,
                                                                  UnitOfWorkWithReference <TModel, TIdentity> unitOfWork,
                                                                  ImportWorker <TModel> worker)
            where TModel : class, new()
        {
            if (method != ImportMethod.InsertOnly)
            {
                return(true);
            }

            var valid = true;

            foreach (var pair in worker.Models)
            {
                TModel    product        = pair.Value;
                TIdentity importedUnique = unitOfWork.GetIdentity(product);

                if (unitOfWork.All.ContainsKey(importedUnique))
                {
                    valid = false;
                    worker.AddKeyDuplicatedError(pair.Key);
                }
            }
            return(valid);
        }
Example #2
0
        private static bool InsertAndUpdate <TModel, TIdentity>(
            UnitOfWorkWithReference <TModel, TIdentity> unitOfWork,
            ImportWorker <TModel> worker)
            where TModel : class, new()
        {
            foreach (var pair in worker.Models)
            {
                TModel    product        = pair.Value;
                TIdentity importedUnique = unitOfWork.GetIdentity(product);

                TModel target = null;
                if (unitOfWork.All.TryGetValue(importedUnique, out target))
                {
                    Model.CopyTo(product, target, false);
                    unitOfWork.RegisterDirty(target);
                }
                else
                {
                    unitOfWork.RegisterNew(product);
                }
            }
            Model.SetUpdateBy(unitOfWork.New.Concat(unitOfWork.Dirty), worker.LoginUserId);

            return(worker.Models.Any());
        }
Example #3
0
        public static bool Import <TModel, TIdentity>(this ImportMethod method,
                                                      UnitOfWorkWithReference <TModel, TIdentity> unitOfWork,
                                                      ImportWorker <TModel> worker)
            where TModel : class, new()
        {
            switch (method)
            {
            case ImportMethod.Replace: return(Replace(unitOfWork, worker));

            case ImportMethod.InsertOnly: return(InsertOnly(unitOfWork, worker));

            case ImportMethod.InsertAndUpdate: return(InsertAndUpdate(unitOfWork, worker));

            default: throw new InvalidOperationException();
            }
        }
Example #4
0
        private static bool Replace <TModel, TIdentity>(
            UnitOfWorkWithReference <TModel, TIdentity> unitOfWork,
            ImportWorker <TModel> worker)
            where TModel : class, new()
        {
            foreach (var pair in worker.Models)
            {
                TModel    product        = pair.Value;
                TIdentity importedUnique = unitOfWork.GetIdentity(product);

                TModel target = null;
                if (unitOfWork.All.TryGetValue(importedUnique, out target))
                {
                    Model.CopyTo(product, target, false);
                    unitOfWork.RegisterDirty(target);
                }
                else
                {
                    unitOfWork.RegisterNew(product);
                }
            }
            IEnumerable <TModel> newAndDirty = unitOfWork.Dirty.Concat(unitOfWork.New);

            Model.SetUpdateBy(newAndDirty, worker.LoginUserId);
            foreach (TModel model in unitOfWork.All.Values.Except(newAndDirty))
            {
                unitOfWork.RegisterRemoved(model);
            }

            if (worker.RecordCount != worker.Models.Count)
            {
                worker.Models.Clear(); // 全件取込不可
            }

            return(worker.Models.Any());
        }
Example #5
0
        public async Task <ImportResult> ImportAsync(string csvPath,
                                                     ImportMethod method,
                                                     CancellationToken?token,
                                                     IProgress <int> progress)
        {
            IEnumerable <TModel> original = (LoadAsync == null) ? Enumerable.Empty <TModel>() : await LoadAsync();

            if (token?.IsCancellationRequested ?? false)
            {
                return(null);
            }
            progress?.Report(20); // 進捗:取込対象データ読込完了

            var unitOfWork = new UnitOfWorkWithReference <TModel, TIdentity>(
                original, createIdentity);

            var worker = new ImportWorker <TModel>(RowDef);

            worker.LoginUserId      = UserId;
            worker.LoginUserCode    = UserCode;
            worker.LoginCompanyId   = CompanyId;
            worker.LoginCompanyCode = CompanyCode;

            await InitializeWorker?.Invoke(worker);

            var valid = true;
            var csv   = Parser.Parse(csvPath);

            RowDef.SetupFields();
            var fieldDefs = RowDef.Fields
                            .Where(f => !f.Ignored)
                            .OrderBy(f => f.FieldNumber)
                            .ToArray();

            foreach (var fields in csv.Skip(RowDef.StartLineNumber))
            {
                worker.NewRecord(fields);
                if (fields.Length < fieldDefs.Length)
                {
                    foreach (var field in fieldDefs.Skip(fields.Length))
                    {
                        Errors.Add(new WorkingReport
                        {
                            LineNo    = worker.RecordCount,
                            FieldNo   = field.FieldIndex,
                            FieldName = field.FieldName,
                            Value     = string.Empty,
                            Message   = $"{field.FieldName}がありません。",
                        });
                    }
                }
                valid &= RowDef.Do(worker); // 書式チェック&エラー情報収集

                if (worker.Reports.Any())
                {
                    Errors.AddRange(worker.Reports);
                    worker.Reports.Clear();
                }
            }
            progress?.Report(40); // 進捗:CSVファイル読込完了

            // DB関連チェック
            var validate = new CodeToIdWorker <TModel>(worker); // importの結果を引き渡す

            valid &= RowDef.Do(validate);                       // DBチェック&エラー情報収集
            Errors.AddRange(validate.Reports);

            await AdditionalWorker?.Invoke(worker);

            var additionalValidate = new AdditionalValidationWorker <TModel>(worker)
            {
                ImportMethod = method,
            };

            valid &= RowDef.Do(additionalValidate); // DBチェック&エラー情報収集
            Errors.AddRange(additionalValidate.Reports);

            foreach (var lineNo in Errors.Where(x => x.LineNo.HasValue).Select(x => x.LineNo.Value).Distinct())
            {
                worker.Models.Remove(lineNo);
            }

            // DB重複チェック
            if (!method.ValidateDuplicated(unitOfWork, worker))
            {
                worker.Reports.ForEach(r => worker.Models.Remove(r.LineNo.Value));
                Errors.AddRange(worker.Reports);
                worker.Reports.Clear();
            }

            // ファイル内キー重複チェック
            var uniqueKeys = new Dictionary <TIdentity, int>();

            var duplicatedLines = new List <int>();

            foreach (var pair in validate.Models)
            {
                // 必須項目が空欄の時は、Nullまたはゼロになっている。
                // キー項目が部分的にでも空欄の場合、重複チェックをパスする。
                var identity = createIdentity(pair.Value);
                if (ContainsNull(identity))
                {
                    identity = default(TIdentity);
                }
                if (identity == null || identity.Equals(default(TIdentity)))
                {
                    continue;
                }

                if (uniqueKeys.ContainsKey(identity))
                {
                    switch (RowDef.DuplicateAdoption)
                    {
                    case DuplicateAdoption.BothAreErrors:
                        var duplicated = uniqueKeys[identity];
                        if (!duplicatedLines.Contains(duplicated))
                        {
                            duplicatedLines.Add(duplicated);
                        }
                        duplicatedLines.Add(pair.Key);
                        break;

                    case DuplicateAdoption.First:
                        duplicatedLines.Add(pair.Key);
                        break;
                    }
                }
                else
                {
                    uniqueKeys.Add(identity, pair.Key);
                }
                if (token.HasValue && token.Value.IsCancellationRequested)
                {
                    return(null);
                }
            }
            progress?.Report(60); // 進捗:データベース関連チェック完了

            switch (RowDef.TreatDuplicateAs)
            {
            case TreatDuplicateAs.Error:
                duplicatedLines.ForEach(lineNo =>
                {
                    Errors.Add(new WorkingReport()     // キー重複
                    {
                        LineNo    = lineNo,
                        FieldName = RowDef.KeyFields?.FirstOrDefault().FieldName ?? string.Empty,
                        Message   = "重複しているため、インポートできません。",
                        Value     = createIdentity(validate.Models[lineNo]).ToString(),
                    });
                });
                break;

            case TreatDuplicateAs.Ignore:
                // エラーにはせず、ここで取込対象から取り除く。
                duplicatedLines.ForEach(lineNo => worker.Ignore(lineNo));
                break;
            }
            if (token.HasValue && token.Value.IsCancellationRequested)
            {
                return(null);
            }

            // エラーデータを更新対象から取り除く
            var errorLines = Errors
                             .GroupBy(report => report.LineNo)
                             .Select(g => g.Key)
                             .ToList();

            if (errorLines.Any(lineNo => !lineNo.HasValue))
            {
                validate.Models.Clear();
            }
            else
            {
                errorLines.ForEach(lineNo => validate.Models.Remove(lineNo.Value));
            }
            if (token.HasValue && token.Value.IsCancellationRequested)
            {
                return(null);
            }
            progress?.Report(80); // 進捗:すべてのデータチェック完了

            ImportResult result = null;

            if (method.Import(unitOfWork, worker) && RegisterAsync != null)
            {
                result = await RegisterAsync(unitOfWork);

                PostImportHanlder?.Invoke(worker, result);
                Debug.Assert(result != null,
                             $"{nameof(RegisterAsync)}()が{nameof(ImportResult)}を返しませんでした。");
            }
            else // 登録処理をしなかった、または取込可能件数がゼロ
            {
                result = new ImportResult
                {
                    ProcessResult = new ProcessResult {
                        Result = true
                    },
                    InsertCount = 0,
                    UpdateCount = 0,
                    DeleteCount = 0,
                };
            }
            Errors.AddRange(worker.Reports);

            if (Errors.Any() && !string.IsNullOrWhiteSpace(ErrorLogPath))
            {
                OutputErrorLog(ErrorLogPath, Errors, csvPath);
            }
            result.ValidItemCount   = worker.Models.Count;
            result.InvalidItemCount = worker.RecordCount - result.ValidItemCount;

            UnitOfWork = unitOfWork;
            progress?.Report(100); // 進捗:取込完了

            return(result);
        }