Свойства условной навигации в Entity Framework Core - PullRequest
0 голосов
/ 20 февраля 2019

Я пытаюсь создать свойство навигации в EF Core, которое установило бы его ссылку условно на основе значений двух свойств.Я не уверен, возможно ли это вообще.

Позвольте мне показать вам пример: допустим, у меня есть иерархическая структура сущностей, таких как Country, State, County и City.У меня также есть объект с именем Law, который может быть «принадлежащим» любому из иерархических объектов.

Итак, я создаю перечисление:

public enum OwnerType
{
    Country,
    State,
    County,
    City
}

... и класс Law:

public class Law
{
    public int Id { get; set; }
    public OwnerType OwnerType { get; set; }
    public int OwnerId { get; set; }
}

Теперь я хочу настроить Lawкласс, чтобы иметь свойство навигации, которое связывало бы OwnerId с первичным ключом соответствующего объекта на основе значения OwnerType.

Я подумал добавить его в класс Law:

public virtual object Owner { get; set; }

Или для создания IOwner интерфейса, который будет реализовывать каждая из иерархических сущностей, а затем я добавлю это вместо этого:

public virtual IOwner Owner { get; set; }

Но тогда я понятия не имею, как настроить EntityTypeConfiguration с EntityTypeBuilder.Это, очевидно, не сработает:

builder.HasOne(x => x.Owner).WithMany(x => x.Laws).HasForeignKey(x => x.OwnerId);

Я просто не знаю, как выполнить то, что я пытаюсь сделать здесь.Есть идеи?

1 Ответ

0 голосов
/ 20 февраля 2019

Как я вижу, у вас есть 4 разных отношения, и вы хотите обрабатывать их одним внешним ключом, что является плохой идеей в концепции.Если у вас есть 4 отношения - вам нужно иметь 4 FK.

В чистом ООП вы можете использовать и интерфейс IOwner, но Entity Framework требует явной информации для сопоставления ваших отношений соответственно, и я считаю, что это лучший способ.Просто добавьте 4 различных обнуляемых FK и подтвердите состояние Law со значением OwnerType.

public class Law {
    public int Id { get; set; }
    public OwnerType OwnerType { get; set; }

    [ForeignKey(nameof(Country)]
    public int? CountryId { get; set; }
    public Country Country { get; set; }

    [ForeignKey(nameof(State)]
    public int? StateId { get; set; }
    public State State { get; set; }

    [ForeignKey(nameof(County)]
    public int? CountyId { get; set; }
    public County County { get; set; }

    [ForeignKey(nameof(City)]
    public int? CityId { get; set; }
    public City City { get; set; }

    private void Validate() {
        switch (OwnerType)
        {
            case OwnerType.Coutnry:
                if(CountryId == null)
                    throw new LawValidationException("Country is requried");
            break;
            case OwnerType.State:
                if(StateId == null)
                    throw new LawValidationException("State is requried");
            break;
            case OwnerType.County:
                if(CountyId == null)
                    throw new LawValidationException("County is requried");
            break;
            case OwnerType.City:
                if(CityId == null)
                    throw new LawValidationException("City is requried");
            break;
            default:
                    throw new LawValidationException("Invalid law owner type");
        }
    }
}

Этот подход решает вашу проблему, идеально подходит для возможностей Entity Framework и может быть легко интегрирован во внешнюю логику, включая модульные тесты.

...