/// <summary> /// 실적 파일 데이터를 추가한다. (동일한 업무 영역에 추가된 실적 파일 데이터가 있다면 삭제 처리된다.) /// </summary> public bool InsertDataFileSource(DataFileSource fileSource) { fileSource.ThrowIfNull(nameof(fileSource)); string procCommandName = "up_DataFileSource_Insert"; try { var command = Connection.GetStoredProcCommand(procCommandName); Connection.AddInParameter(command, "FormID", DbType.Guid, fileSource.FormId); Connection.AddInParameter(command, "FormSectionID", DbType.Guid, fileSource.FormSectionId); Connection.AddInParameter(command, "FileSourceID", DbType.Guid, fileSource.FileSourceId); Connection.AddInParameter(command, "FileTemplateID", DbType.Guid, fileSource.FileTemplateId); Connection.AddInParameter(command, "HtmlTemplateID", DbType.Guid, fileSource.HtmlTemplateId); Connection.AddInParameter(command, "CreatorId", DbType.String, fileSource.CreatorId); Connection.AddInParameter(command, "FileName", DbType.String, fileSource.FileName); Connection.AddInParameter(command, "Extension", DbType.String, fileSource.Extension); Connection.AddInParameter(command, "Size", DbType.Int64, fileSource.Size); Connection.AddInParameter(command, "Path", DbType.String, fileSource.FileRelativePath); Connection.AddInParameter(command, "Comment", DbType.String, fileSource.Comment); Connection.AddInParameter(command, "CreatedDate", DbType.DateTimeOffset, fileSource.CreatedDate); Connection.AddInParameter(command, "SourceDate", DbType.DateTimeOffset, fileSource.SourceDate); return((int)Connection.ExecuteNonQuery(command) > 0); } catch (Exception ex) { throw new DataException($"프로시져 실행 중 예기치 못한 에러가 발생했습니다.\r\n 프로시저: \"{procCommandName}\"", ex); } }
/// <summary> /// 기간에 해당되는 실적 파일 데이터를 셀렉트한다. /// </summary> public IEnumerable <DataFileSource> SelectDataFileSourceListBySourceDateRange(Guid formId, Guid formSectionId, DateTimeOffset beginDate, DateTimeOffset endDate) { string procCommandName = "up_DataFileSource_SelectBySourceDateRange"; try { var command = Connection.GetStoredProcCommand(procCommandName); Connection.AddInParameter(command, "FormID", DbType.Guid, formId); Connection.AddInParameter(command, "FormSectionID", DbType.Guid, formSectionId); Connection.AddInParameter(command, "BeginDate", DbType.DateTimeOffset, beginDate); Connection.AddInParameter(command, "EndDate", DbType.DateTimeOffset, endDate); using (DataSet ds = Connection.ExecuteDataSet(command)) { ValidateTableCount(ds, 1); List <DataFileSource> dataFileSourceList = null; if (ds.Tables[0].Rows.Count > 0) { dataFileSourceList = new List <DataFileSource>(); foreach (DataRow dr in ds.Tables[0].Rows) { dataFileSourceList.Add(DataFileSource.ParseFrom(dr)); } } return(dataFileSourceList); } } catch (Exception ex) { throw new DataException($"프로시져 실행 중 예기치 못한 에러가 발생했습니다.\r\n 프로시저: \"{procCommandName}\"", ex); } }
/// <summary> /// 실적 파일 데이터를 셀렉트한다. /// </summary> public DataFileSource SelectDataFileSource(Guid formId, Guid formSectionId, Guid fileSourceId) { string procCommandName = "up_DataFileSource_Select"; try { var command = Connection.GetStoredProcCommand(procCommandName); Connection.AddInParameter(command, "FormID", DbType.Guid, formId); Connection.AddInParameter(command, "FormSectionID", DbType.Guid, formSectionId); Connection.AddInParameter(command, "FileSourceID", DbType.Guid, fileSourceId); using (DataSet ds = Connection.ExecuteDataSet(command)) { ValidateTableCount(ds, 1); if (ds.Tables[0].Rows.Count > 0) { return(DataFileSource.ParseFrom(ds.Tables[0].Rows[0])); } return(null); } } catch (Exception ex) { throw new DataException($"프로시져 실행 중 예기치 못한 에러가 발생했습니다.\r\n 프로시저: \"{procCommandName}\"", ex); } }
/// <summary> /// 대시보드 테이블 업무 영역을 반환한다. /// </summary> public FormTableSection SelectFormTableSection(Guid formId, Guid formSectionId) { string procCommandName = "up_FormTableSection_Select"; try { var command = Connection.GetStoredProcCommand(procCommandName); Connection.AddInParameter(command, "FormID", DbType.Guid, formId); Connection.AddInParameter(command, "FormSectionID", DbType.Guid, formSectionId); using (DataSet ds = Connection.ExecuteDataSet(command)) { ValidateTableCount(ds, 4); // 1. 업무 영역 if (ds.Tables[0].Rows.Count > 0) { var formSection = FormTableSection.ParseFrom(ds.Tables[0].Rows[0]); // 2. 파일 템플릿 정보 if (ds.Tables[1].Rows.Count > 0) { formSection.FileTemplate = DataFileTemplate.ParseFrom(ds.Tables[1].Rows[0]); } // 3. 파일 소스 정보 if (ds.Tables[2].Rows.Count > 0) { formSection.FileSource = DataFileSource.ParseFrom(ds.Tables[2].Rows[0]); } // 4. 데이터 업로더 정보 foreach (DataRow dr in ds.Tables[3].Rows) { var uploader = DataFileSourceUploader.ParseFrom(dr); formSection.FileSourceUploaders[uploader.UserId] = uploader; } return(formSection); } return(null); } } catch (Exception ex) { throw new DataException($"프로시져 실행 중 예기치 못한 에러가 발생했습니다.\r\n 프로시저: \"{procCommandName}\"", ex); } }
static void testHirarchySetQueries(DataFileSource src) { foreach (var c in src.Table <Customer>().ToEnumerable()) { foreach (var o in c.OrdersSet) { foreach (var ol in o.OrderLinesSet) { Debug.WriteLine( Thread.CurrentThread.Name + ">>" + c.Name + " bought " + ol.Detail + ":" + ol.Price); } } } }
// ReSharper disable once UnusedParameter.Local static void Main(string[] args) { // simplify connection creation by referring file path and immediately start using data // ReSharper disable once UnusedVariable // ReSharper disable once StringLiteralTypo var srcNew = new DataFileSource(StartupPath + @"\testDB.accdb"); var src = new DataFileSource(StartupPath + @"\testDB.mdb") { ReuseConnection = true }; // Run a query into a data-set, reflection not involved yet var dataSet = src.GetDataSet("select * from customers"); dataSet.Dispose(); // We can use linq to a data-set-wrapper and then assign anonymous types instead of defining reflect-able tables var wrappedSet = src.GetDataSetWrapper("select * from customers"); var linqEnumFromDataSet = from line in wrappedSet select new { CustomerName = (string)line["CustomerName"], City = (string)line["City"] }; foreach (var linqLine in linqEnumFromDataSet) { Debug.WriteLine(linqLine.CustomerName + " from " + linqLine.City); } // We can access tables by defining record classes var customers = src.Table <Customer>(); var orders = src.Tables.Get <Order>(); var orderLines = src.Table <OrderLine>(); // Run a static function over the table class to get a list of records and join-lists populated with data var customersList = ReflectedTable <Customer> .ToListFillJoins(src); var wasSameTableInstanceUtilized = customersList[0].AtTable == customers; // should be true // We can utilize these instances for quick select queries, enumerations as well as joins var jerome = customers.LikeList("%jer%").FirstOrDefault(); // the line instances can be used to modify the data if (jerome != null) { jerome.ZipCode++; jerome.Update(); // test sql insert. var newOrder = orders.Insert(new Order { customerID = jerome.ID, OrderShipped = true }); // insert var newOrderCopy = orders.Get(newOrder.ID); // query Debug.Assert(newOrder.customerID == newOrderCopy.customerID); // verify data Debug.Assert(newOrder.OrderShipped == newOrderCopy.OrderShipped); // Query into enumerable without table definition directly on data source. Reflection is performed to identify returned fields // this query uses a simple class definition without any attributes foreach (var detailAndPrice in src.SelectUnattributed <DetailAndPrice>("OrderLines", null)) { Debug.WriteLine( "detail: " + detailAndPrice.Detail + "\t ,price:" + detailAndPrice.Price); } // Using an attributed reflected class - define the join relationship as a parameter to the function to return a list of results var selectJoinList = src.SelectList <CustomSelectJoinLine>( "(Customers LEFT JOIN Orders ON Customers.ID = Orders.customerID)" + "LEFT JOIN OrderLines ON Orders.ID = OrderLines.orderID", null); // Get a list from an sql query built by a tool. The line type of the returned list is defined by a class var customerAndSumList = src.SelectList <CustomerAndSum>( @"SELECT DISTINCTROW Customers.CustomerName, Sum(OrderLines.Price) AS [Sum Of Price] FROM (Customers LEFT JOIN Orders ON Customers.[ID] = Orders.[customerID]) LEFT JOIN OrderLines ON Orders.[ID] = OrderLines.[orderID] GROUP BY Customers.CustomerName;"); // test select-unattributed-list, no where var detailAndPriceList = src.SelectUnattributedList <DetailAndPrice>("OrderLines", null); // Run queries utilizing reflection and hierarchies defined by JoinSet classes // in the following test, data-readers are enumerated and not cached as memory lists foreach (var c in customers.ToEnumerable()) { foreach (var o in c.OrdersSet) { foreach (var ol in o.OrderLinesSet) { Debug.WriteLine( c.Name + " bought " + ol.Detail + ":" + ol.Price); } } } // test table-join with different syntax foreach (var joinTableLine in src.Join <Customer, Order>("customerID")) { Debug.WriteLine( joinTableLine.l.Name + " bought on " + joinTableLine.r.OrderDate); } foreach (var joinTableLine in src.Table <Customer>().JoinEn <Order>(-1, "customerID", null, null)) { Debug.WriteLine( joinTableLine.l.Name + " bought on " + joinTableLine.r.OrderDate); } // reuse join sets to perform group foreach (var joinedGroupedLine in src.Join <Customer, Order, OrderLine>( "customerID", "orderID").Group( "Customers.ID", "CustomerName", SqlFunction.Sum, "Price", null)) { Debug.WriteLine(joinedGroupedLine.extraField + " owes: " + joinedGroupedLine.functionField); } // run enumeration of hierarchy join-set relationships when several threads are involved var testThreads = new Thread[10]; for (var i = 0; i < testThreads.Length; i++) { testThreads[i] = new Thread(() => testHirarchySetQueries(src)) { Name = "thread " + i }; } // ReSharper disable once ForCanBeConvertedToForeach for (var i = 0; i < testThreads.Length; i++) { testThreads[i].Start(); } // ReSharper disable once ForCanBeConvertedToForeach for (var i = 0; i < testThreads.Length; i++) { testThreads[i].Join(); } // the same test over several threads in a 2000 access data file testThreads = new Thread[10]; for (var i = 0; i < testThreads.Length; i++) { testThreads[i] = new Thread(() => testHirarchySetQueries(src)) { Name = "thread " + i }; } // ReSharper disable once ForCanBeConvertedToForeach for (var i = 0; i < testThreads.Length; i++) { testThreads[i].Start(); } // ReSharper disable once ForCanBeConvertedToForeach for (var i = 0; i < testThreads.Length; i++) { testThreads[i].Join(); } // test source clone, and get data set over custom sql var srcClone = src.Clone(); var dataSet2 = srcClone.GetDataSet("select * from customers"); srcClone.Dispose(); dataSet2.Dispose(); // Use indexing to query for a record and update a record var someone = customers[customerAndSumList[0].CustomerName]; someone.ZipCode++; customers[someone.Name] = someone; // easy code to insert new records into tables, doesn't keep an in memory reference orderLines.Insert(new OrderLine { orderID = newOrder.ID, Detail = "test123", Price = 23.4m }); orderLines.Insert(new OrderLine { orderID = newOrder.ID, Detail = "delete123", Price = 23.4m }); // utilize the ReflectedTableLine fill join mechanism to fill the empty list with data from storage newOrder.FillJoin("OrderLines"); // delete new order and related order lines src.Delete("OrderLines", "orderID", newOrder.ID); newOrder.Delete(); } // test fill joins to fill in-memory lists with data foreach (var c in customersList) { c.FillJoins(); foreach (var o in c.Orders) { o.FillJoins(); } } // at this point should have an in memory tree of all customers->orders->order-lines var editOrderLine = customersList.Last().Orders.Last().OrderLines.LastOrDefault(); if (editOrderLine != null) { editOrderLine.Price = 44.21m; orderLines.Update(editOrderLine); // use table instance to call update } else { var lastOrder = customersList.Last().Orders.Last(); orderLines.Insert(new OrderLine { orderID = lastOrder.ID, Detail = "stack of papers", Price = 43.22m }); } // test access to xlsx file, reuse the same reflected table classes var xlsxTest = new DataFileSource(StartupPath + @"\Customers.xlsx"); var xlsxCustomersTable = xlsxTest.Tables.Get <Customer>(); var xlsxCustomersTable2ndInstance = xlsxTest.Table <Customer>(); // alternative syntax Debug.Assert(xlsxCustomersTable == xlsxCustomersTable2ndInstance); var xlsxCustomersList = xlsxCustomersTable.ToList(); xlsxCustomersList[0].ZipCode++; xlsxCustomersList[0].Update(); // create table, drop table and copy records from one source to the other var dataTableNames = xlsxTest.GetDataTableNames(); if (dataTableNames.Contains("Orders")) { xlsxTest.Table <Order>().DropDataTable(); } xlsxTest.Table <Order>().CreateDataTable(); foreach (var o in orders.ToEnumerable()) { xlsxTest.Table <Order>().Insert(o); } // test export to excel if (File.Exists(StartupPath + @"\Customers1.xlsx")) { File.Delete(StartupPath + @"\Customers1.xlsx"); } var newXlsxTest = new DataFileSource(StartupPath + @"\Customers1.xlsx"); newXlsxTest.Table <Customer>().CreateDataTable(); newXlsxTest.Dispose(); //xlsxTest.Table<Order>().DropDataTable(); // test access to local sql server express database // testSqlServer(orders); }
/// <summary> /// 파일 소스를 등록한다. 같은 기간에 등록된 파일 소스가 있다면 삭제 처리 된다. /// </summary> public bool AddDataFileSource(DataFileSource fileSource) { fileSource.ThrowIfNull(nameof(fileSource)); fileSource.Validate(); using (var service = new FormTableService(CurrentUser)) { // 1. FormTable, FormTableSection 체크 var formTable = service.GetFormTable(fileSource.FormId); if (formTable == null) { throw new ObjectNotFoundException($"업로드 대상이 되는 대시보드 테이블을 찾을 수 없습니다.\r\n대시보드 ID: \"{fileSource.FormId}\""); } else if (!formTable.IsEnabled || formTable.IsDeleted) { string state = formTable.IsDeleted ? "삭제" : "비활성화"; throw new InvalidOperationException($"대상 대시보드 테이블이 {state} 된 상태이므로 파일 데이터를 업로드 할 수 없습니다.\r\n대시보드 ID: \"{fileSource.FormId}\""); } var formSection = service.GetFormTableSection(fileSource.FormId, fileSource.FormSectionId); if (formSection == null) { throw new ObjectNotFoundException($"업로드 대상이 되는 업무 영역을 찾을 수 없습니다.\r\n업무영역 ID: \"{fileSource.FormSectionId}\""); } else if (!formSection.IsEnabled || formSection.IsDeleted) { string state = formTable.IsDeleted ? "삭제" : "비활성화"; throw new InvalidOperationException($"대상 업무 영역이 {state} 된 상태이므로 파일 데이터를 업로드 할 수 없습니다.\r\n업무영역 ID: \"{fileSource.FormSectionId}\""); } fileSource.FileTemplateId = formSection.FileTemplate.FileTemplateId; fileSource.HtmlTemplateId = formTable.HtmlTemplateId; using (var repo = new DashboardRepository()) { // 3. 실제 파일 경로 체크 string filePath = fileSource.GetFileAbsolutePath(DiskPathForDataFileSource); if (!File.Exists(filePath)) { logger.Error($"업로드 된 데이터 파일 소스를 찾을 수 없습니다. 파일 경로: \"{filePath}\""); throw new FileNotFoundException($"파일을 찾을 수 없습니다. 파일: \"{fileSource.FileName}\""); } var allValues = new List <DataFileCellValue>(); ExcelFileType fileType; // 4. 파일 타입 체크 if (!Enum.TryParse <ExcelFileType>(fileSource.Extension, true, out fileType)) { throw new FileLoadException($"지원하지 않는 엑셀 파일 타입입니다. 파일: \"{fileSource.FileName}\""); } // 5. 엑셀로부터 값을 읽음 using (var parser = new ExcelParser(filePath, fileType)) { var parseOption = formSection.FileTemplate.ParseOption; foreach (var kv in parseOption.Sheets) { foreach (var sheetOption in kv.Value) { string sheetName = kv.Key; var values = parser.GetValuesFromSheet(kv.Key, sheetOption, () => { return(new DataFileCellValue(fileSource.FileSourceId, sheetName) { CreatedDate = fileSource.CreatedDate }); }).Cast <DataFileCellValue>() .ToList(); allValues.AddRange(values); } } if (!allValues.Any()) { logger.Warn($"업로드 된 데이터 파일로부터 읽어들인 엑셀 값이 없습니다. 파일: \"{fileSource.FileName}\"" + $"\r\n\r\n" + $"{fileSource}"); } } // 6. DB에 추가 repo.BeginTransaction(); try { // 6. 이미 동일한 기간에 해당되는 파일이 있는지 체크 // => 있다면 삭제 var dateRange = formTable.GetDateRangeByUploadInterval(fileSource.SourceDate); var oldFileSourceList = repo.SelectDataFileSourceListBySourceDateRange(fileSource.FormId, fileSource.FormSectionId, dateRange.BeginDate, dateRange.EndDate); if (oldFileSourceList != null) { var duplicated = oldFileSourceList .Where(o => o.FileSourceId != fileSource.FileSourceId) .ToArray(); if (duplicated.Any()) { logger.Warn($"해당 기간에 파일 소스가 2개 이상 존재합니다. 파일: {duplicated.Select(o => o.FileName).ToString()}" + $"\r\n\r\n" + $"업무 영역 ID: \"{fileSource.FormSectionId}\"" + $"\r\n" + $"기간: \"{dateRange.BeginDate.ToString("yyyy-MM-dd")}\" ~ \"{dateRange.EndDate.ToString("yyyy-MM-dd")}\""); if (duplicated.Any(o => o.IsConfirmed)) { // 관리자급 권한이 없다면 오류 처리 (관리자는 컨펌된 데이터가 있더라도 업로드 가능하도록 요청) if (CurrentUser.GroupType < UserPermissionGroupType.Administrator) { if (dateRange.BeginDate.ToString("yyyy-MM-dd").Equals(dateRange.EndDate.ToString("yyyy-MM-dd"))) { throw new InvalidOperationException($"대상 기간에 이미 최종 컨펌된 데이터가 있습니다." + $"\r\n" + $"기간: \"{dateRange.BeginDate.ToString("yyyy-MM-dd")}\""); } else { throw new InvalidOperationException($"대상 기간에 이미 최종 컨펌된 데이터가 있습니다." + $"\r\n" + $"기간: \"{dateRange.BeginDate.ToString("yyyy-MM-dd")}\" ~ \"{dateRange.EndDate.ToString("yyyy-MM-dd")}\""); } } } foreach (var o in duplicated) { if (repo.DeleteDataFileSource( formId: o.FormId, formSectionId: o.FormSectionId, fileSourceId: o.FileSourceId, deleterId: CurrentUser.UserId, deletedDate: DateTimeOffset.Now)) { logger.Warn($"새로운 데이터를 업로드 하기 위해 대상 기간에 해당되는 데이터 파일이 삭제되었습니다. 파일: \"{o.FileName}\"" + $"\r\n\r\n" + $"기간: \"{dateRange.BeginDate}\" ~ \"{dateRange.EndDate}\"" + $"\r\n\r\n" + $"{o}"); } } } } // 7 파일 데이터 추가 if (repo.InsertDataFileSource(fileSource)) { if (allValues.Any()) { repo.InsertDataFileCellValueList(formTable.FormId, formSection.FormSectionId, fileSource.FileSourceId, allValues, allValues.First().CreatedDate); } repo.CommitTransaction(); logger.Info($"새 데이터 파일을 추가하였습니다. 파일: \"{fileSource.FileName}\"" + $"\r\n\r\n" + $"{fileSource}"); return(true); } } catch (Exception ex) { logger.Error(ex, $"데이터 파일 추가 중 알 수 없는 오류가 발생하였습니다. 대시보드: \"{formSection.FormName}\", 업무영역: \"{formSection.FormSectionName}\"" + $"\r\n\r\n" + $"{formSection}"); try { repo.RollBackTransaction(); } catch (Exception rex) { logger.Fatal(ex, $"데이터 파일 추가 중 치명적인 오류가 발생하였습니다. 대시보드: \"{formSection.FormName}\", 업무영역: \"{formSection.FormSectionName}\"" + $"\r\n\r\n" + $"{formSection}"); ExceptionDispatchInfo.Capture(rex).Throw(); // not reached } ExceptionDispatchInfo.Capture(ex).Throw(); } return(false); // not reached } } }
/// <summary> /// 페이징 처리된 실적 파일 데이터 리스트를 반환한다. /// </summary> /// <param name="queryUserId">값이 있는 경우, 해당 유저가 접근 가능한 데이터만 반환</param> public PagedModel <DataFileSource> SelectDataFileSourcePagedList(DataFileSourceSearchOption option, string queryUserId = null) { string procCommandName = "up_DataFileSource_SelectPagedList"; try { var command = Connection.GetStoredProcCommand(procCommandName); Connection.AddInParameter(command, "PageNumber", DbType.Int32, option.PageNumber); Connection.AddInParameter(command, "PageCount", DbType.Int32, option.PageCount); Connection.AddInParameter(command, "SortBy", DbType.String, option.SortBy); Connection.AddInParameter(command, "OrderBy", DbType.String, option.OrderBy.ToEnumMemberString()); if (option.FormId.HasValue) { Connection.AddInParameter(command, "FormID", DbType.Guid, option.FormId.Value); } Connection.AddInParameter(command, "SearchKeyword", DbType.String, option.SearchKeyword); Connection.AddInParameter(command, "QueryUserID", DbType.String, queryUserId); using (DataSet ds = Connection.ExecuteDataSet(command)) { ValidateTableCount(ds, 2); var result = new PagedModel <DataFileSource>(option) { PagingOption = option }; int totalCount = 0; // 1. 유저 정보 테이블 var userInfoMap = new Dictionary <string, UserInfo>(StringComparer.OrdinalIgnoreCase); foreach (DataRow dr in ds.Tables[1].Rows) { var userInfo = UserInfo.ParseFrom(dr); userInfoMap[userInfo.UserId] = userInfo; } // 2. 데이터 파일 리스트 var dataFileSourceList = new List <DataFileSource>(); foreach (DataRow dr in ds.Tables[0].Rows) { var dataFile = DataFileSource.ParseFrom(dr, out totalCount); UserInfo userInfo = null; if (userInfoMap.TryGetValue(dataFile.CreatorId, out userInfo)) { dataFile.CreatorInfo = userInfo; } else { dataFile.CreatorInfo = new UserInfo(dataFile.CreatorId); } dataFileSourceList.Add(dataFile); } result.TotalCount = totalCount; result.Items = dataFileSourceList; return(result); } } catch (Exception ex) { throw new DataException($"프로시져 실행 중 예기치 못한 에러가 발생했습니다.\r\n 프로시저: \"{procCommandName}\"", ex); } }
/// <summary> /// 페이징 처리된 대시보드 테이블 업무 영역을 반환한다. /// </summary> public PagedModel <FormTableSection> SelectFormTableSectionPagedList(PagingOption option) { string procCommandName = "up_FormTableSection_SelectPagedList"; try { var command = Connection.GetStoredProcCommand(procCommandName); Connection.AddInParameter(command, "PageNumber", DbType.Int32, option.PageNumber); Connection.AddInParameter(command, "PageCount", DbType.Int32, option.PageCount); Connection.AddInParameter(command, "SortBy", DbType.String, option.SortBy); Connection.AddInParameter(command, "OrderBy", DbType.String, option.OrderBy.ToEnumMemberString()); using (DataSet ds = Connection.ExecuteDataSet(command)) { ValidateTableCount(ds, 4); var result = new PagedModel <FormTableSection>(option) { PagingOption = option }; int totalCount = 0; // 1. 업무 영역 foreach (DataRow dr in ds.Tables[0].Rows) { var formSection = FormTableSection.ParseFrom(dr, out totalCount); result.Items.Add(formSection); } // 2. 파일 템플릿 정보 foreach (DataRow dr in ds.Tables[1].Rows) { var fileTemplate = DataFileTemplate.ParseFrom(dr); var formSections = result.Items.FindAll(o => o.FileTemplateId == fileTemplate.FileTemplateId); if (formSections.Any()) { formSections.ForEach(o => { o.FileTemplate = fileTemplate; }); } } // 3. 파일 소스 정보 foreach (DataRow dr in ds.Tables[2].Rows) { var fileSource = DataFileSource.ParseFrom(dr); var formSections = result.Items.FindAll(o => o.FormId == fileSource.FormId && o.FormSectionId == fileSource.FormSectionId); if (formSections.Any()) { formSections.ForEach(o => { o.FileSource = fileSource; }); } } // 4. 데이터 업로더 정보 foreach (DataRow dr in ds.Tables[3].Rows) { var uploader = DataFileSourceUploader.ParseFrom(dr); var formSections = result.Items.FindAll(o => o.FormId == uploader.FormId && o.FormSectionId == uploader.FormSectionId); if (formSections.Any()) { formSections.ForEach(o => { o.FileSourceUploaders[uploader.UserId] = uploader; }); } } result.TotalCount = totalCount; return(result); } } catch (Exception ex) { throw new DataException($"프로시져 실행 중 예기치 못한 에러가 발생했습니다.\r\n 프로시저: \"{procCommandName}\"", ex); } }
/// <summary> /// 대시보드 테이블 업무 영역 리스트를 반환한다. /// </summary> /// <param name="queryUserId">값이 있는 경우, 해당 유저가 접근 가능한 데이터만 반환</param> /// <param name="fileSourceDateRanges">값이 있는 경우, 해당 날짜의 데이터 파일 소스 정보를 반환</param> public IEnumerable <FormTableSection> SelectFormTableSectionList(Guid?formId, string queryUserId = null, List <DataDateRange> fileSourceDateRanges = null) { string procCommandName = "up_FormTableSection_SelectList"; try { var command = Connection.GetStoredProcCommand(procCommandName); if (formId.HasValue) { Connection.AddInParameter(command, "FormID", DbType.Guid, formId.Value); } Connection.AddInParameter(command, "QueryUserID", DbType.String, queryUserId); if (fileSourceDateRanges != null) { // 특정한 날짜 범위 내의 데이터 소스 값만 반환하기 위해 날짜 범위를 DB에 전달한다. using (var spParamDateRanges = new DataTable()) // type_DataSourceDateRanges { spParamDateRanges.Columns.Add("UploadInterval", typeof(string)); spParamDateRanges.Columns.Add("BeginDate", typeof(DateTimeOffset)); spParamDateRanges.Columns.Add("EndDate", typeof(DateTimeOffset)); spParamDateRanges.Columns.Add("IsCurrentData", typeof(bool)); foreach (var dateRange in fileSourceDateRanges) { spParamDateRanges.Rows.Add(new object[] { dateRange.UploadInterval, dateRange.BeginDate, dateRange.EndDate, dateRange.IsCurrentData }); } var param = command.Parameters.AddWithValue("SourceDateRanges", spParamDateRanges); param.SqlDbType = SqlDbType.Structured; } } using (DataSet ds = Connection.ExecuteDataSet(command)) { ValidateTableCount(ds, 4); var result = new List <FormTableSection>(); // 1. 업무 영역 foreach (DataRow dr in ds.Tables[0].Rows) { var formSection = FormTableSection.ParseFrom(dr); result.Add(formSection); } // 2. 파일 템플릿 정보 foreach (DataRow dr in ds.Tables[1].Rows) { var fileTemplate = DataFileTemplate.ParseFrom(dr); var formSections = result.FindAll(o => o.FileTemplateId == fileTemplate.FileTemplateId); if (formSections.Any()) { formSections.ForEach(o => { o.FileTemplate = fileTemplate; }); } } // 3. 파일 소스 정보 foreach (DataRow dr in ds.Tables[2].Rows) { var fileSource = DataFileSource.ParseFrom(dr); bool isCurrentData = dr.Get <bool>("IsCurrentData"); var formSections = result.FindAll(o => o.FormId == fileSource.FormId && o.FormSectionId == fileSource.FormSectionId); if (formSections.Any()) { formSections.ForEach(o => { if (isCurrentData) { o.FileSource = fileSource; } else { o.PrevFileSource = fileSource; } }); } } // 4. 데이터 업로더 정보 foreach (DataRow dr in ds.Tables[3].Rows) { var uploader = DataFileSourceUploader.ParseFrom(ds.Tables[3].Rows[0]); var formSections = result.FindAll(o => o.FormId == uploader.FormId && o.FormSectionId == uploader.FormSectionId); if (formSections.Any()) { formSections.ForEach(o => { o.FileSourceUploaders[uploader.UserId] = uploader; }); } } return(result); } } catch (Exception ex) { throw new DataException($"프로시져 실행 중 예기치 못한 에러가 발생했습니다.\r\n 프로시저: \"{procCommandName}\"", ex); } }