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

ЖАНРЫ

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

}

}

Свойство

FullName
допускает
null
, т.к. до сохранения в базе данных новые сущности не будут иметь установленных значений. Финальная конфигурация свойства
Fullname
обеспечивается с использованием Fluent API.

Сущность Car(Inventory)

Для таблицы

Inventory
был создан шаблон сущностного класса по имени
Inventory
, но имя
Car
предпочтительнее. Исправить ситуацию легко: измените имя файла на
Car.cs
и имя класса на
Car
. Атрибут
[Table]
применяется корректно, так что нужно просто добавить схему
dbo
. Обратите внимание, что параметр
Schema
необязателен, поскольку по умолчанию для SQL Server принимается
dbo
, но он был включен ради полноты:

[Table("Inventory", Schema = "dbo")]

[Index(nameof(MakeId), Name = "IX_Inventory_MakeId")]

public partial class Car : BaseEntity

{

...

}

Обновите операторы

using
следующим образом:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.ComponentModel.DataAnnotations;

using System.ComponentModel.DataAnnotations.Schema;

using System.Text.Json.Serialization;

using AutoLot.Models.Entities.Base;

using Microsoft.EntityFrameworkCore;

Унаследуйте класс

Car
от
BaseEntity
, после чего удалите свойства
Id
и
TimeStamp
, конструктор и директиву
#pragma nullable disable
. Вот как выглядит код класса после таких изменений:

namespace AutoLot.Models.Entities

{

[Table("Inventory", Schema = "dbo")]

[Index(nameof(MakeId), Name = "IX_Inventory_MakeId")]

public partial class Car : BaseEntity

{

public int MakeId { get; set; }

[Required]

[StringLength(50)]

public string Color { get; set; }

[Required]

[StringLength(50)]

public string PetName { get; set; }

[ForeignKey(nameof(MakeId))]

[InverseProperty("Inventories")]

public virtual Make Make { get; set; }

[InverseProperty(nameof(Order.Car))]

public virtual ICollection<Order> Orders { get; set; }

}

}

В коде все еще присутствуют проблемы, которые необходимо устранить. Свойства

Color
и
PetName
определены как не допускающие
null
, но их значения не устанавливаются в конструкторе или не инициализируются в определении свойств. Проблема решается с помощью инициализаторов свойств. Кроме того, добавьте к свойству
PetName
атрибут
[DisplayName]
, чтобы сделать название свойства более удобным для восприятия человеком. Обновите свойства, как показано ниже (изменения выделены полужирным):

[Required]

[StringLength(50)]

public string Color { get; set; } = "Gold";

[Required]

[StringLength(50)]

[DisplayName("Pet Name")]

public string PetName { get; set; } = "My Precious";

На

заметку!
Атрибут
[DisplayName]
используется инфраструктурой ASP.NET Core и будет описан в части VIII.

Навигационное свойство

Make
потребуется переименовать в
MakeNavigation
и сделать допускающим
null
, а в обратном навигационном свойстве вместо "магической" строки должно применяться выражение
nameof
языка С#. Наконец, нужно удалить модификатор
virtual
. После всех модификаций свойство приобретает следующий вид:

[ForeignKey(nameof(MakeId))]

[InverseProperty(nameof(Make.Cars))]

public Make? MakeNavigation { get; set; }

На заметку! Модификатор

virtual
необходим для ленивой загрузки. Поскольку ленивая загрузка в примерах книги не используется, модификатор
virtual
будет удаляться из всех свойств внутри уровня доступа к данным.

Для навигационного свойства

Orders
требуется атрибут
[Jsonlgnore]
, чтобы предотвратить циклические ссылки JSON при сериализации объектной модели. В шаблонном коде обратное навигационное свойство задействует выражение
nameof
, но его понадобится обновить, т.к. имена всех навигационных свойств типа ссылок будут содержать суффикс
Navigation
. Последнее изменение связано с тем, что свойство должно иметь тип
IEnumerable<Order>
, а не
ICollection<Order>
, и инициализироваться с применением нового экземпляра
List<Order>
. Изменение не является обязательным, потому что
ICollection<Order>
тоже будет работать. Более низкоуровневый тип
IEnumerable<T>
предпочтительнее использовать с навигационными свойствами типа коллекций
IEnumerable<T>
(поскольку интерфейсы
IQueryable<T>
и
ICollection<T>
унаследованы от
IEnumerable<T>
). Модифицируйте код, как показано далее:

[JsonIgnore]

[InverseProperty(nameof(Order.CarNavigation))]

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

Затем добавьте свойство

NotMapped
, которое будет отображать значение
Make
экземпляра
Car
, устранив необходимость в классе
CarViewModel
из главы 21. Если связанная информация
Make
была извлечена из базы данных с записью
Car
, то значение
MakeName
отображается. Если связанные данные не были извлечены, тогда для свойства отображается строка Unknown (т.е. производитель не известен). Как вы должны помнить, свойства с атрибутом
[NotMapped]
не относятся к базе данных и существуют только внутри сущности. Добавьте следующий код:

[NotMapped]

public string MakeName => MakeNavigation?.Name ?? "Unknown";

Переопределите

ToString
для отображения информации о транспортном средстве:

public override string ToString

{

// Поскольку столбец PetName может быть пустым,
.

// определить стандартное имя **No Name**

return $"{PetName ?? "**No Name**"} is a {Color} {MakeNavigation?.Name}

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