Ответ
Да, работал. Shadow properties — это свойства, которые не определены в классе вашей модели, но существуют в модели EF Core и сопоставлены со столбцами базы данных.
Типичные сценарии использования:
- Аудит: Автоматическое отслеживание
CreatedDateиModifiedDate. - Мягкое удаление: Флаг
IsDeleted. - Внешние ключи (FK): Для отношений, где навигационное свойство есть, но явное свойство FK в классе не требуется.
Пример настройки и использования:
// В DbContext.OnModelCreating
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property<DateTime>("LastUpdated") // Определяем shadow property
.HasDefaultValueSql("GETUTCDATE()");
modelBuilder.Entity<Blog>()
.Property<bool>("IsDeleted");
}
// Как получить или установить значение shadow property
var blog = context.Blogs.First();
// Получаем значение
var lastUpdated = context.Entry(blog).Property<DateTime>("LastUpdated").CurrentValue;
// Устанавливаем значение
context.Entry(blog).Property<bool>("IsDeleted").CurrentValue = true;
Ключевые моменты:
- Доступ к ним осуществляется через
DbContext.Entry(entity).Property<T>("PropertyName"). - Они могут использоваться в запросах LINQ через статический метод
EF.Property. - Полезны для инфраструктурных данных, которые не должны быть частью публичного API доменной модели.
Ответ 18+ 🔞
А, ну shadow properties, да, работал, конечно. Это такие свойства, которые в твоём классе модели нихуя не объявлены, но EF Core их в своей внутренней модели держит и в базу колонки под них рисует. Хитро, да? Как будто призраки какие-то.
Где эта хуйня пригождается:
- Аудит: Чтобы не писать каждый раз руками, когда запись создали или обосрали. Автоматом проставляются
CreatedDateиModifiedDate. - Мягкое удаление: Чтоб не удалять нахуй, а просто выставлять флажок
IsDeleted. Удобно, потом можно всё откатить, как будто ничего и не было. - Внешние ключи: Когда навигационное свойство у тебя есть, а вот явно хранить айдишник в классе — лень или некрасиво. EF Core сам тебе этот FK в тени создаст, маньяк скрытный.
Вот смотри, как это выглядит в деле:
// Ковыряемся в OnModelCreating
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property<DateTime>("LastUpdated") // Вот он, призрак! Объявляем прямо по имени строкой.
.HasDefaultValueSql("GETUTCDATE()"); // И сразу дефолтное значение из базы прикрутили.
modelBuilder.Entity<Blog>()
.Property<bool>("IsDeleted"); // Ещё один невидимка для мягкого удаления.
}
// А вот как с этими призраками общаться, когда нужно
var blog = context.Blogs.First();
// Вытаскиваем значение, как контрабанду
var lastUpdated = context.Entry(blog).Property<DateTime>("LastUpdated").CurrentValue;
// Засовываем новое значение
context.Entry(blog).Property<bool>("IsDeleted").CurrentValue = true;
Важные моменты, чтоб не обосраться:
- Доступ к ним — только через вот эту штуку
DbContext.Entry(entity).Property<T>("PropertyName"). По-другому никак, они же в тени, блядь. - В LINQ-запросах их можно использовать, но через статический метод
EF.Property. Иначе компилятор тебя не поймёт, он же про призраков не в курсе. - Вообще, идея в том, чтобы всякую служебную хрень, типа дат аудита или флагов удаления, не таскать в публичном API твоей модели. Пусть живут тихо, на задворках EF Core, не мозоля глаза. Удобная хуйня, если использовать с умом.