Konfiguracja zbiorcza modelu

Jeśli aspekt musi być skonfigurowany w taki sam sposób w wielu typach jednostek, poniższe techniki umożliwiają zmniejszenie duplikowania kodu i konsolidację logiki.

Zobacz pełny przykładowy projekt zawierający fragmenty kodu przedstawione poniżej.

Konfiguracja zbiorcza w modelu OnModelCreating

Każdy obiekt konstruktora zwrócony Model z ModelBuilder uwidacznia właściwość lubMetadata, która zapewnia niski poziom dostępu do obiektów, które składają się na model. W szczególności istnieją metody, które umożliwiają iterowanie określonych obiektów w modelu i stosowanie do nich wspólnej konfiguracji.

W poniższym przykładzie model zawiera typ Currencywartości niestandardowej:

public readonly struct Currency
{
    public Currency(decimal amount)
        => Amount = amount;

    public decimal Amount { get; }

    public override string ToString()
        => $"${Amount}";
}

Właściwości tego typu nie są domyślnie odnajdywane, ponieważ bieżący dostawca EF nie wie, jak mapować go na typ bazy danych. Ten fragment kodu OnModelCreating dodaje wszystkie właściwości typu Currency i konfiguruje konwerter wartości do obsługiwanego typu : decimal

foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
    foreach (var propertyInfo in entityType.ClrType.GetProperties())
    {
        if (propertyInfo.PropertyType == typeof(Currency))
        {
            entityType.AddProperty(propertyInfo)
                .SetValueConverter(typeof(CurrencyConverter));
        }
    }
}
public class CurrencyConverter : ValueConverter<Currency, decimal>
{
    public CurrencyConverter()
        : base(
            v => v.Amount,
            v => new Currency(v))
    {
    }
}

Wady interfejsu API metadanych

  • W przeciwieństwie do interfejsu API Fluent każda modyfikacja modelu musi być wykonywana jawnie. Jeśli na przykład niektóre Currency właściwości zostały skonfigurowane jako nawigacja zgodnie z konwencją, musisz najpierw usunąć nawigację odwołującą się do właściwości CLR przed dodaniem właściwości typu jednostki. #9117 poprawi to.
  • Konwencje są uruchamiane po każdej zmianie. Jeśli usuniesz nawigację odnalezioną zgodnie z konwencją, konwencja zostanie uruchomiona ponownie i będzie mogła ją ponownie dodać. Aby temu zapobiec, należy opóźnić konwencje do momentu dodania właściwości przez wywołanie DelayConventions() metody , a później zdysponować zwrócony obiekt lub oznaczyć właściwość CLR jako ignorowaną przy użyciu polecenia AddIgnored.
  • Typy jednostek mogą zostać dodane po wykonaniu tej iteracji, a konfiguracja nie zostanie do nich zastosowana. Zwykle można temu zapobiec, umieszczając ten kod na końcu OnModelCreatingelementu , ale jeśli masz dwa współzależne zestawy konfiguracji, może nie istnieć kolejność, która pozwoli na spójne ich stosowanie.

Konfiguracja przed konwencją

Program EF Core 6.0 umożliwia jednokrotne określenie konfiguracji mapowania dla danego typu CLR; ta konfiguracja jest następnie stosowana do wszystkich właściwości tego typu w modelu podczas ich odnajdowania. Jest to nazywane "konfiguracją modelu przed konwencją", ponieważ konfiguruje aspekty modelu, które są następnie używane przez konwencje tworzenia modelu. Taka konfiguracja jest stosowana przez zastąpienie ConfigureConventions typu pochodzącego z klasy DbContext.

W tym przykładzie pokazano, jak skonfigurować wszystkie właściwości typu Currency tak, aby miały konwerter wartości:

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    configurationBuilder
        .Properties<Currency>()
        .HaveConversion<CurrencyConverter>();
}

W tym przykładzie pokazano, jak skonfigurować niektóre aspekty dla wszystkich właściwości typu string:

configurationBuilder
    .Properties<string>()
    .AreUnicode(false)
    .HaveMaxLength(1024);

Uwaga

Typ określony w wywołaniu z ConfigureConventions może być typem podstawowym, interfejsem lub definicją typu ogólnego. Wszystkie pasujące konfiguracje będą stosowane w kolejności od najmniej określonych:

  1. Interfejs
  2. Typ podstawowy
  3. Definicja typu ogólnego
  4. Typ wartości niepustej
  5. Dokładny typ

Ignorowanie typów

Konfiguracja przed konwencją umożliwia również ignorowanie typu i uniemożliwia odnajdywanie go przez konwencje jako typ jednostki lub jako właściwość typu jednostki:

configurationBuilder
    .IgnoreAny(typeof(IList<>));

Domyślne mapowanie typów

Ogólnie rzecz biorąc, program EF może tłumaczyć zapytania za pomocą stałych typu, który nie jest obsługiwany przez dostawcę, o ile określono konwerter wartości dla właściwości tego typu. Jednak w zapytaniach, które nie obejmują żadnych właściwości tego typu, nie ma możliwości znalezienia poprawnego konwertera wartości przez program EF. W takim przypadku można wywołać metodę DefaultTypeMapping , aby dodać lub zastąpić mapowanie typu dostawcy:

configurationBuilder
    .DefaultTypeMapping<Currency>()
    .HasConversion<CurrencyConverter>();

Ograniczenia konfiguracji przed konwencją

  • Nie można skonfigurować wielu aspektów przy użyciu tego podejścia. #6787 rozszerzy ten element do większej liczby typów.
  • Obecnie konfiguracja jest określana tylko przez typ CLR. #20418 zezwala na niestandardowe predykaty.
  • Ta konfiguracja jest wykonywana przed utworzeniem modelu. Jeśli wystąpią jakiekolwiek konflikty podczas stosowania, ślad stosu wyjątków nie będzie zawierać ConfigureConventions metody, więc znalezienie przyczyny może być trudniejsze.