Проект "Отпуск сотрудников". Часть 1, база данных.
!!НАШ БЛОГ ПЕРЕЕХАЛ!!
Мы создали свой сайт! Все материалы, опубликованные в этом блоге, переехали туда.
Наш новый сайт maddevelop.ru
Сначала сделаем серверную часть проекта. В решении создадим новый проект "Веб-приложение ASP.NET Core". Далее выберем шаблон "API".
Создание моделей
У нас будет три таблицы: "Сотрудники", "Цвета" и "Отпуски". У сотрудника (employee) есть идентификатор, имя и идентификатор цвета, которым будет окрашиваться его отпуски в сводной таблице. У цвета (color) имеются идентификатор и числовой номер, по которому можно будет воссоздать структуру Color, предназначенную для раскраски чего-либо. Специально не стал хранить название цвета в столбце типа string, ведь использование int позволяет занимать таблице меньше места в памяти. Таблицы "Цвета" и "Сотрудники" связаны отношением "один-ко-многим". У отпуска (vacation) есть обязательный идентификатор, дата начала отпуска, его продолжительность и ключ работника, которому "принадлежит" отпуск. Сотрудники и отпуски связаны отношением "один-ко-многим". Нулевым может быть только столбец с именем человека, остальные обязательны к заполнению.
Для создания базы данных и таблиц в ней будем использовать Entity Framework Core (далее просто EF). Подход выберем "code first", то есть по нашим классам, объявленным в C#, EF создаст базу данных вместе с необходимыми таблицами и связями. Для моделей сделаем отдельную папку Models.
Класс сотрудника:
public class Employee { public int EmployeeId { get; set; } public string Name { get; set; } public List<Vacation> Vacations { get; set; } public int ColorId { get; set; } [JsonIgnore] public Color Color { get; set; } }
Класс цвета:
public class Color { public int ColorId { get; set; } public int ColorNumber { get; set; } public List<Employee> Employees { get; set; } }
Класс отпуска:
public class Vacation { public int VacationId { get; set; } public DateTime Start { get; set; } public int Duration { get; set; } public int EmployeeId { get; set; } [JsonIgnore] public Employee Employee { get; set; } }
Использование свойства Vacations в классе Employee и свойств EmployeeId и Employee в классе Vacation сообщает EF, что между соответствующими таблицами необходимо создать отношение "один-ко-многим". Аналогичным образом создаётся и связь между Color и Employee.
Для создания самих таблиц используется класс контекста, где они формируются на основании свойств:
public class ApplicationDbContext : DbContext { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } public DbSet<Employee> Employees { get; set; } public DbSet<Vacation> Vacations { get; set; } public DbSet<Color> Colors { get; set; } }
Строку подключения базы данных следует указать в файле appsettings.json. Если такого файла не в проекте, то его можно создать вручную.
{ "ConnectionStrings": { "vacationConnection": "Server=(localdb)\\mssqllocaldb;Database=vacationsstore; Trusted_Connection=True" } }
Здесь "vacationsstore" - имя базы данных, которое можно задать любым.
Создание класса контекста с нужной строкой подключения следует зарегистрировать в провайдере сервисов в методе ConfigureServices() класса Startup. Сам метод выглядит следующим образом:
public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. // Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { string connection = Configuration.GetConnectionString("vacationConnection"); services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connection)); services.AddSingleton<IEmployeeRepository, EFEmployeeRepository>(); services.AddMvc(); } // This method gets called by the runtime. // Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseStatusCodePages(); app.UseDeveloperExceptionPage(); app.UseStaticFiles(); app.UseMvcWithDefaultRoute(); SeedData.EnsurePopulated(app); } }
Также создадим класс с методом, который будет сразу заполнять нашу базу данных начальными значениями.
public static class SeedData { public static void EnsurePopulated(IApplicationBuilder app) { ApplicationDbContext context = app.ApplicationServices.GetRequiredService<ApplicationDbContext>(); context.Database.Migrate(); if (!context.Employees.Any()) { context.Colors.AddRange( new Color { ColorNumber = -16777216 }, // чёрный new Color { ColorNumber = -16744448 }, // зелёный new Color { ColorNumber = -16776961 }, // синий new Color { ColorNumber = -65536 }, // красный new Color { ColorNumber = -256 }, // жёлтый new Color { ColorNumber = -8388480 }, // фиолетовый new Color { ColorNumber = -23296 }, // оранжевый new Color { ColorNumber = -8355712 }, // серый new Color { ColorNumber = -16711936 }, // лайм new Color { ColorNumber = -16181 } // розовый ); context.SaveChanges(); context.Employees.AddRange( new Employee { Name = "Pyotr", Color = context.Colors.Skip(0).FirstOrDefault() }, new Employee { Name = "Sergey", Color = context.Colors.Skip(1).FirstOrDefault() }, new Employee { Name = "Vasiliy", Color = context.Colors.Skip(2).FirstOrDefault() } ); context.SaveChanges(); context.Vacations.AddRange( new Vacation { Start = new DateTime(2019, 5, 6), Duration = 7, Employee = context.Employees.Skip(0).FirstOrDefault() }, new Vacation { Start = new DateTime(2019, 3, 11), Duration = 7, Employee = context.Employees.Skip(0).FirstOrDefault() }, new Vacation { Start = new DateTime(2019, 5, 1), Duration = 28, Employee = context.Employees.Skip(1).FirstOrDefault() }, new Vacation { Start = new DateTime(2019, 4, 30), Duration = 7, Employee = context.Employees.Skip(2).FirstOrDefault() }, new Vacation { Start = new DateTime(2019, 5, 12), Duration = 7, Employee = context.Employees.Skip(2).FirstOrDefault() }, new Vacation { Start = new DateTime(2019, 5, 25), Duration = 7, Employee = context.Employees.Skip(2).FirstOrDefault() } ); context.SaveChanges(); } } }
В первой строчке метода мы получаем класс контекста из провайдера сервисов. Затем производим все необходимые миграции. Если база данных с именем из строки подключения отсутствует, то она создаётся. При пустой таблице Employees мы заполняем все таблицы данными. Метод EnsurePopulated() следует вызывать в методе Configure() класса Startup. В результате данные таблиц будут такими:
И, наконец, в методе CreateWebHostBuilder() класса Program сконфигурируем провайдер сервисов:
public class Program { public static void Main(string[] args) { CreateWebHostBuilder(args).Build().Run(); } public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>() .UseDefaultServiceProvider(options => options.ValidateScopes = false); }
Таким образом, с помощью Entity Framework Core мы создали базу данных и заполнили её таблицы минимальной информацией. В следующей части определим класс репозитория и класс контроллера.
Ещё больше интересной информации на нашем Telegram-канале.
......... >> К части 2 >>