Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен
Шрифт:
Интервал:
Закладка:
[ForeignKey(nameof(CarId))]
[InverseProperty(nameof(Car.Orders))]
public Car? CarNavigation { get; set; }
[ForeignKey(nameof(CustomerId))]
[InverseProperty(nameof(Customer.Orders))]
public Customer? CustomerNavigation { get; set; }
На этом сущностный класс Order завершен.
На заметку! В данный момент проект должен нормально компилироваться. Проект AutoLot.Dal не скомпилируется до тех пор, пока не будет обновлен класс ApplicationDbContext.
Сущность SeriLogEntry
База данных нуждается в дополнительной таблице для хранения журнальных записей. В проектах ASP.NET Core из части VIII будет применяться инфраструктура ведения журналов SeriLog, и один из вариантов предусматривает помещение журнальных записей в таблицу SQL Server. Хотя таблица будет использоваться через несколько глав, имеет смысл добавить ее сейчас.
Эта таблица не связана ни с одной из остальных таблиц и не задействует класс BaseEntity. Добавьте в каталог Entities новый файл класса по имени SeriLogEntry.cs и поместите в него следующий код:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Xml.Linq;
namespace AutoLot.Models.Entities
{
[Table("SeriLogs", Schema = "Logging")]
public class SeriLogEntry
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string? Message { get; set; }
public string? MessageTemplate { get; set; }
[MaxLength(128)]
public string? Level { get; set; }
[DataType(DataType.DateTime)]
public DateTime? TimeStamp { get; set; }
public string? Exception { get; set; }
public string? Properties { get; set; }
public string? LogEvent { get; set; }
public string? SourceContext { get; set; }
public string? RequestPath { get; set; }
public string? ActionName { get; set; }
public string? ApplicationName { get; set; }
public string? MachineName { get; set; }
public string? FilePath { get; set; }
public string? MemberName { get; set; }
public int? LineNumber { get; set; }
[NotMapped]
public XElement? PropertiesXml
=> (Properties != null)? XElement.Parse(Properties):null;
}
}
Итак, сущностный класс SeriLogEntry закончен.
На заметку! Свойство TimeStamp в сущностном классе SeriLogEntry отличается от свойства TimeStamp в классе BaseEntity. Имена совпадают, но в этой таблице оно хранит дату и время регистрации записи в журнале (что будет конфигурироваться как стандартная настройка SQL Server), а не rowversion в других сущностях.
Класс ApplicationDbContext
Пришло время обновить файл ApplicationDbContext.cs. Начните с приведения операторов using к такому виду:
using System;
using System.Collections;
using System.Collections.Generic;
using AutoLot.Models.Entities;
using AutoLot.Models.Entities.Owned;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using AutoLot.Dal.Exceptions;
Файл начинается с конструктора без параметров. Удалите его, т.к. он не нужен. Следующий конструктор принимает экземпляр DbContextOptions и пока подходит. Перехватчики событий для DbContext и ChangeTracker добавляются позже в главе.
Свойства DbSet<T> необходимо сделать допускающими null, имена скорректировать, а модификаторы virtual удалить. Теперь новую сущность для ведения журнала необходимо добавить. Перейдите к свойствам DbSet<T> и модифицируйте их следующим образом:
public DbSet<SeriLogEntry>? LogEntries { get; set; }
public DbSet<CreditRisk>? CreditRisks { get; set; }
public DbSet<Customer>? Customers { get; set; }
public DbSet<Make>? Makes { get; set; }
public DbSet<Car>? Cars { get; set; }
public DbSet<Order>? Orders { get; set; }
Обновление кода Fluent API
Код Fluent API находится в переопределенной версии метода OnModelCreating() и использует экземпляр класса ModelBuilder для обновления модели.
Сущность SeriLogEntry
Первое изменение, вносимое в метод OnModelCreating(), касается добавления кода Fluent API для конфигурирования сущности SeriLogEntry. Свойство Properties является XML-столбцом SQL Server, а свойство TimeStamp отображается в SQL Server на столбец datetime2 со стандартным значением, установленным в результат функции getdate() из SQL Server. Добавьте в метод OnModelCreating() следующий код:
modelBuilder.Entity<SeriLogEntry>(entity =>
{
entity.Property(e => e.Properties).HasColumnType("Xml");
entity.Property(e => e.TimeStamp).HasDefaultValueSql("GetDate()");
});
Сущность CreditRisk
Далее понадобится модифицировать код сущности CreditRisk. Блок конфигурирования для столбца TimeStamp удаляется, т.к. столбец конфигурируется в BaseEntity. Код конфигурирования навигации должен быть скорректирован с учетом новых имен. Кроме того, выполняется утверждение о том, что навигационное свойство не равно null. Другое изменение связано с конфигурированием свойства типа принадлежащей сущности, чтобы сопоставить с именами столбцов для FirstName и LastName, и добавлением вычисляемого значения для свойства FullName. Ниже показан обновленный блок для сущности CreditRisk с изменениями, выделенными полужирным:
modelBuilder.Entity<CreditRisk>(entity =>
{
entity.HasOne(d => d.CustomerNavigation)
.WithMany(p => p!.CreditRisks)
.HasForeignKey(d => d.CustomerId)
.HasConstraintName("FK_CreditRisks_Customers");
entity.OwnsOne(o => o.PersonalInformation,
pd =>
{
pd.Property<string>(nameof(Person.FirstName))
.HasColumnName(nameof(Person.FirstName))
.HasColumnType("nvarchar(50)");
pd.Property<string>(nameof(Person.LastName))
.HasColumnName(nameof(Person.LastName))
.HasColumnType("nvarchar(50)");
pd.Property(p => p.FullName)
.HasColumnName(nameof(Person.FullName))
.HasComputedColumnSql("[LastName] + ', ' + [FirstName]");
});
});
Сущность Customer
Следующим обновляется блок для сущности Customer. Здесь удаляется код для TimeStamp и конфигурируются свойства принадлежащего сущностного класса:
modelBuilder.Entity<Customer>(entity =>
{
entity.OwnsOne(o => o.PersonalInformation,
pd =>
{
pd.Property(p => p.FirstName).HasColumnName(nameof(Person.FirstName));
pd.Property(p => p.LastName).HasColumnName(nameof(Person.LastName));
pd.Property(p => p.FullName)
.HasColumnName(nameof(Person.FullName))
.HasComputedColumnSql("[LastName] + ', ' + [FirstName]");
});
});
Сущность Make
Для сущности Make необходимо модифицировать блок конфигурирования, удалив