Экспорт модели в .xlsx соблюдая SOLID

174
08 декабря 2016, 22:42

В БД есть таблица результатов тестирования по русскому языку и математике (SubjectCode=2):

dbo.Result

Во второй таблице находятся просто сведения о школах:

dbo.School

Таких результатов бывает 40.000-70.000. Нужно на выходе получить для каждого тестируемого вот такой отчет в pdf-файле:

Мое решение:

  1. Создал Excel-шаблон;
  2. Беру данные из базы и заношу их в этот xlsx-шаблон;
  3. Сохраняю этот шаблон в pdf-файл;
  4. И так для каждого ученика.

LearnerReport.cs

namespace so16092016.Models
{
    public class LearnerReport
    {
        public string SNS { get; set; } //Surname Name SecondName
        public string SchoolName { get; set; }
        public string ClassName { get; set; }
        public int TestResult5 { get; set; }
    }
}

Program.cs

using Excel = Microsoft.Office.Interop.Excel;
namespace so16092016
{
    class Program
    {
        static void Main(string[] args)
        {
            resultsEntities context = new resultsEntities();
            ResultsRepository resultsRepository = new ResultsRepository(context);
            var ma_results = resultsRepository.GetTList().Where(x => x.SubjectCode == 2); //получить результаты по математике
            Excel.Application app = new Excel.Application();
            app.DisplayAlerts = false;
            Excel.Workbook book_template = app.Workbooks.Open(@"шаблон_отчета.xlsx");
            Excel._Worksheet sheet_template = book_template.Sheets["отчет"];
            foreach(var ob in ma_results)
            {
                //1. Создаем объкт LearnerReport из БД
                LearnerReport report = new LearnerReport
                {
                    SNS = $"{ob.surname} {ob.name} {ob.SecondName}",
                    SchoolName = ob.SchoolName,
                    ClassName = ob.ClassName,
                    TestResult5 = ob.TestResult5                     
                };
                //2. Экспорт объкта LearnerReport в шаблон xlsx
                sheet_template.Range["C4"].Value2 = report.SNS;
                sheet_template.Range["C5"].Value2 = report.SchoolName;
                sheet_template.Range["C6"].Value2 = report.ClassName;
                sheet_template.Range["C9"].Value2 = report.TestResult5;
                //3. Сохраняем полученный файл в .pdf на рабочем столе
                string file_name = $@"{Environment.GetFolderPath(Environment.SpecialFolder.Desktop)}\{report.SNS}.pdf";
                sheet_template.ExportAsFixedFormat(Excel.XlFixedFormatType.xlTypePDF, file_name);
            }
            book_template.Close(0);
            book_template = null;
            app.Quit();
            app = null;
        }
    }
}

Необходимо: Приложение работает и дает необходимый результат. Но вы наверное видите, что оно далеко от ООП (SOLID) и как результат очень трудно его "допиливать" и масштабировать. Помогите правильно спроектировать данный механизм формирования подобных отчетов:

  • логика экспорта модели в .xlsx должна быть у самой модели или необходимо создать отдельный класс-менеджер для этого?
  • какие должны быть модели?
  • как правильно создавать модель-отчета на основе объектов БД?
  • какой порождающий паттерн здесь больше подходит?
Answer 1

Конкретно в вашем случай нет необходимость, применять какие либо паттерны, т.к. у вас довольно простая программа и паттерны добавят лишь ненужную сложность (применять паттерны ради паттернов плохая практика). Паттерны сгодятся если вы пишите большие Enterprise приложения, где необходима гибкость и масштабируемость.

Если я правильно понял, то вы хотите отрефакторить программу.

1) Из кода я не понял что вы используете для получения данных из БД, но посоветовал бы использовать какую нибудь ORM, например Entity Framework 6.

Создать DbContext и использовать его в репозиториях ResultsRepository и SchoolRepository Все выборки засунуть в соответствующий репозиторий например

class ResultsRepository
{
    // возвращает все результаты
    public IEnumerable<Result> GetResults()
    // возвращает все результаты по заданому предмету.
    public IEnumerable<Result> GetResults(Subject subject)
    // возвращает все результаты для заданой школы.
    public IEnumerable<Result> GetResults(int idSchool)
    // возвращает все результаты для заданой школы по заданому предмету.
    public IEnumerable<Result> GetResults(int idSchool, Subject subject)    
}
class SchoolRepository
{
    // возвращает список всех школ.
    public IEnumerable<School> GetSchools()
}

2) Модель данных приблизительно выглядит так

class Result 
{
    [Key]
    public Guid Id { get; set; }
    public string Surname { get; set; }
    public string Name { get; set; }
    public string SecondName { get; set; }
    [NotMapped]
    public string SNS => $"{Surname} {Name} {SecondName}";
    public School School { get; set; }
    public string ClassName { get; set; }
    public Subject Subject { get; set; }
    public int TestResult5 { get; set; }
}
class School
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }
}
enum Subject
{
    RussianLanguage = 1,
    Mathematics = 2
}

3) Можно создать отдельный класс для работы отчётами

class LearnerReportManager
{
    public Excel._Worksheet CreateReport(Result result)
    public SaveReport(Excel._Worksheet reportWorksheet, string fileName)
}

4) Для формирования Excel отчёта луче используйте EPPlus или более крутой File Formats от Syncfusion (у них есть бесплатная версия). вы так не будите зависеть от установленного MS Office.

5) Если кол. формируемых отчетов за раз от 40 до 70 тыс., то было бы не плохо добавить многопоточное создание отчетов, это существенно уменьшит время создания отчётов.

READ ALSO
Замена тега со ссылкой на ссылку

Замена тега со ссылкой на ссылку

мне в PHP нужно заменить строку

567
Куда смотреть? (апи постинг в группе)

Куда смотреть? (апи постинг в группе)

Ребят прошу помощи, так как не могу понять как реализовать постинг на стене в группе

371
Построение дерева на php

Построение дерева на php

Существует база данных с информацией об узлах сетиУ некоторых узлов есть дочерние узлы, а у тех в свою очередь могут быть еще дочерние

406