Чтение онлайн

ЖАНРЫ

Язык программирования C#9 и платформа .NET5
Шрифт:

INNER JOIN @inserted0 i ON ([t].[Id] = [i].[Id])

ORDER BY [i].[_Position];

',N'@p0 nvarchar(50),@p1 int,@p2 nvarchar(50),@p3 nvarchar(50),

@p4 int,@p5 nvarchar(50),@
p6 nvarchar(50),@p7 int,@p8 nvarchar(50),

@p9 nvarchar(50),@p10 int,@p11 nvarchar(50)',@
p0=N'Yellow',@p1=1,

@p2=N'Herbie',@p3=N'White',@p4=2,@p5=N'Mach 5',@p6=N'Pink',@p7=3,

@
p8=N'Avon',@p9=N'Blue',@p10=4,@p11=N'Blueberry'

Принадлежащие

сущностные типы

Возможность применения класса C# в качестве свойства сущности с целью определения коллекции свойств для другой сущности впервые появилась в версии EF Core 2.0 и в последующих версиях постоянно обновлялась. Когда типы, помеченные атрибутом

[Owned]
или сконфигурированные посредством Fluent API, добавлены в виде свойств сущности, инфраструктура EF Core добавит все свойства из сущностного класса
[Owned]
к владеющему классу. В итоге увеличивается вероятность многократного использования кода С#.

"За кулисами" EF Core считает результат отношением "один к одному". Принадлежащий класс является зависимой сущностью, а владеющий класс — главной сущностью. Хотя принадлежащий класс рассматривается как сущность, он не может существовать без владеющего класса. Имена столбцов из принадлежащего класса по умолчанию получают формат

ИмяНавигационногоСвойства_ИмяСвойстваПринадлежащейСущности
(например,
PersonalNavigation_FirstName
). Стандартные имена можно изменять с применением Fluent API.

Взгляните на приведенный далее класс Person (обратите внимание на атрибут

[Owned]
):

[Owned]

public class Person

{

[Required, StringLength(50)]

public string FirstName { get; set; } = "New";

[Required, StringLength(50)]

public string LastName { get; set; } = "Customer";

}

Он используется классом

Customer
:

[Table("Customers", Schema = "Dbo")]

public partial class Customer : BaseEntity

{

public Person PersonalInformation { get; set; } = new Person;

[JsonIgnore]

[InverseProperty(nameof(CreditRisk.CustomerNavigation))]

public IEnumerable<CreditRisk> CreditRisks { get; set; } =

new List<CreditRisk>;

[JsonIgnore]

[InverseProperty(nameof(Order.CustomerNavigation))]

public IEnumerable<Order> Orders { get; set; } = new List<Order>;

}

По умолчанию два свойства

Person
отображаются на столбцы с именами
PersonalInformation_FirstName
и
PersonalInformation_LastName
. Чтобы изменить это, добавьте в метод
OnConfiguring
следующий код Fluent API:

modelBuilder.Entity<Customer>(entity =>

{

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)");

});

});

Вот как будет создаваться результирующая таблица (обратите внимание, что допустимость значений

null
в столбцах
FirstName
и
LastName
не соответствует аннотациям данных в принадлежащей сущности
Person
):

CREATE TABLE [dbo].[Customers](

[Id] [int] IDENTITY(1,1) NOT NULL,

[FirstName] [nvarchar](50) NULL,

[LastName] [nvarchar](50) NULL,

[TimeStamp] [timestamp] NULL,

[FullName] AS (([LastName]+', ')+[FirstName]),

CONSTRAINT [PK_Customers] PRIMARY KEY CLUSTERED

(

[Id] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,

IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS
= ON, ALLOW_PAGE_LOCKS = ON,

OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]

) ON [PRIMARY]

GO

Проблема с принадлежащими сущностями, которая может быть не видна вам, но приводить к сложной ситуации, в версии EF Core 5 устранена. Легко заметить, что класс

Person
содержит аннотации данных Required для обоих своих свойств, но оба столбца SQL Server определены как допускающие
NULL
.Так происходит из-за проблемы с тем, каким образом система миграции транслирует принадлежащие сущности, когда они используются с необязательным отношением. Для исправления проблемы потребуется сделать отношение обязательным.

Решить задачу можно двумя способами. Первый — включить допустимость

null
на уровне проекта или в классах С#. Тогда навигационное свойство
PersonalInformation
становится не допускающим значение
null
, что исполняющая среда EF Core учитывает и соответствующим образом конфигурирует столбцы в принадлежащей сущности. Второй способ предусматривает добавление кода Fluent API для того, чтобы сделать навигационное свойство обязательным:

modelBuilder.Entity<Customer>(entity =>

Поделиться с друзьями: