Проект "Отпуск сотрудников". Часть 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 >>