Книги онлайн и без регистрации » Разная литература » Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен

Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 285 286 287 288 289 290 291 292 293 ... 407
Перейти на страницу:
свойство TimeStamp и добавив код, который ограничивает удаление сущности, имеющей зависимые сущности:

modelBuilder.Entity<Make>(entity =>

{

  entity.HasMany(e => e.Cars)

      .WithOne(c => c.MakeNavigation!)

      .HasForeignKey(k => k.MakeId)

      .OnDelete(DeleteBehavior.Restrict)

      .HasConstraintName("FK_Make_Inventory");

});

Сущность Order

Для сущности Order обновите имена навигационных свойств и добавьте утверждение, что обратные навигационные свойства не равны null. Вместо ограничения удалений отношение Customer с Order настраивается на каскадное удаление:

modelBuilder.Entity<Order>(entity =>

{

  entity.HasOne(d => d.CarNavigation)

     .WithMany(p => p!.Orders)

     .HasForeignKey(d => d.CarId)

     .OnDelete(DeleteBehavior.ClientSetNull)

     .HasConstraintName("FK_Orders_Inventory");

  entity.HasOne(d => d.CustomerNavigation)

     .WithMany(p => p!.Orders)

     .HasForeignKey(d => d.CustomerId)

     .OnDelete(DeleteBehavior.Cascade)

     .HasConstraintName("FK_Orders_Customers");

});

Настройте фильтр для свойства CarNavigation сущности Order, чтобы отфильтровывать неуправляемые автомобили. Обратите внимание, что этот код находится не в том же блоке, где был предыдущий код. Никаких формальных причин разносить код не существует; просто здесь демонстрируется альтернативный синтаксис для конфигурирования в отдельных блоках:

modelBuilder.Entity<Order>().HasQueryFilter(e => e.CarNavigation!.IsDrivable);

Сущность Car

Шаблонный класс содержит конфигурацию для класса Inventory, который понадобится изменить на Car. Свойство TimeStamp нужно удалить, а в конфигурации навигационных свойств изменить имена свойств на MakeNavigation и Cars. Сущность получает фильтр запросов для отображения по умолчанию только управляемых автомобилей и устанавливает стандартное значение свойства IsDrivable в true. Код должен иметь следующий вид:

modelBuilder.Entity<Car>(entity =>

{

  entity.HasQueryFilter(c => c.IsDrivable);

  entity.Property(p

    => p.IsDrivable).HasField("_isDrivable").HasDefaultValue(true);

  entity.HasOne(d => d.MakeNavigation)

    .WithMany(p => p.Cars)

    .HasForeignKey(d => d.MakeId)

    .OnDelete(DeleteBehavior.ClientSetNull)

    .HasConstraintName("FK_Make_Inventory");

});

Специальные исключения

Распространенный прием для обработки исключений предусматривает перехват системного исключения (и/или исключения EF Core, как в текущем примере), его регистрацию в журнале и генерацию специального исключения. Если специальное исключение перехватывается вышерасположенным методом, то разработчику известно, что исключение уже было зарегистрировано в журнале, и необходимо только отреагировать на него надлежащим образом в коде.

Создайте в проекте AutoLot.Dal новый каталог по имени Exceptions и поместите в него четыре новых файла классов, CustomException.cs, CustomConcurrencyException.cs, CustomDbUpdateException.cs и CustomRetryLimitExceededException.cs, содержимое которых показано ниже:

// CustomException.cs

using System;

namespace AutoLot.Dal.Exceptions

{

  public class CustomException : Exception

  {

    public CustomException() {}

    public CustomException(string message) : base(message) { }

    public CustomException(string message, Exception innerException)

            : base(message, innerException) { }

  }

}

// CustomConcurrencyException.cs

using Microsoft.EntityFrameworkCore;

namespace AutoLot.Dal.Exceptions

{

  public class CustomConcurrencyException : CustomException

  {

    public CustomConcurrencyException() { }

    public CustomConcurrencyException(string message) : base(message) { }

    public CustomConcurrencyException(

      string message, DbUpdateConcurrencyException innerException)

            : base(message, innerException) { }

  }

}

// CustomDbUpdateException.cs

using Microsoft.EntityFrameworkCore;

namespace AutoLot.Dal.Exceptions

{

  public class CustomDbUpdateException : CustomException

  {

      public CustomDbUpdateException() { }

    public CustomDbUpdateException(string message) : base(message) { }

    public CustomDbUpdateException(

      string message, DbUpdateException innerException)

            : base(message, innerException) { }

  }

}

// CustomRetryLimitExceededException.cs

using System;

using Microsoft.EntityFrameworkCore.Storage;

namespace AutoLot.Dal.Exceptions

{

  public class CustomRetryLimitExceededException : CustomException

  {

    public CustomRetryLimitExceededException() { }

    public CustomRetryLimitExceededException(string message)

        : base(message) { }

    public CustomRetryLimitExceededException(

      string message, RetryLimitExceededException innerException)

        : base(message, innerException) { }

  }

}

На заметку! Обработка специальных исключений была подробно раскрыта в главе 7.

Переопределение метода SaveChanges()

Как обсуждалось в предыдущей главе, метод SaveChanges() базового класса DbContext сохраняет результаты операций изменения, добавления и удаления в базе данных. Переопределение этого метода позволяет инкапсулировать обработку исключений в одном месте. Располагая специальными исключениями, добавьте оператор using для AutoLot.Dal.Exceptions в начало файла ApplicationDbContext.cs, после чего переопределите метод SaveChanges():

public override int SaveChanges()

{

  try

  {

    return base.SaveChanges();

  }

  catch (DbUpdateConcurrencyException ex)

  {

    // Произошла ошибка параллелизма.

    // Подлежит регистрации в журнале и надлежащей обработке.

    throw new CustomConcurrencyException(

        "A concurrency error happened.", ex);

      // Произошла ошибка параллелизма

  }

  catch (RetryLimitExceededException ex)

  {

    // Подлежит регистрации в журнале и надлежащей обработке.

    throw new CustomRetryLimitExceededException(

        "There is a problem with SQl Server.", ex);

      // Возникла проблема c SQL Server

  }

  catch (DbUpdateException ex)

  {

    // Подлежит регистрации в журнале и надлежащей обработке.

    throw new CustomDbUpdateException(

        "An error occurred updating the database", ex);

      // Произошла ошибка при обновлении базы данных

  }

  catch (Exception ex)

  {

    // Подлежит регистрации в журнале и надлежащей обработке.

    throw new CustomException(

        "An error occurred updating the database", ex);

      // Произошла ошибка при обновлении базы данных

  }

}

Обработка событий DbContext и ChangeTracker

Перейдите к конструктору класса ApplicationDbContext и добавьте три события DbContext, которые обсуждались в предыдущей главе:

public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)

  : base(options)

{

  base.SavingChanges += (sender, args) =>

  {

     Console.WriteLine($"Saving changes for {((ApplicationDbContext)

       sender)!.Database!.GetConnectionString()}");

  };

  base.SavedChanges += (sender, args) =>

  {

     Console.WriteLine($"Saved {args!.EntitiesSavedCount} changes for

       {((ApplicationDbContext)sender)!.Database!.GetConnectionString()}");

  };

  base.SaveChangesFailed += (sender, args) =>

  {

    Console.WriteLine(

      $"An exception occurred! {args.Exception.Message} entities");

  };

}

Затем добавьте обработчики для событий StateChanged

1 ... 285 286 287 288 289 290 291 292 293 ... 407
Перейти на страницу:

Комментарии
Минимальная длина комментария - 20 знаков. В коментария нецензурная лексика и оскорбления ЗАПРЕЩЕНЫ! Уважайте себя и других!
Комментариев еще нет. Хотите быть первым?