Внешний ключ с составным ключом в EF Core - PullRequest
0 голосов
/ 30 января 2019

У меня есть следующие классы:

    public class ProductAttribute 
    {
        public Guid ProductId { get; set; }

        public Guid AttributeId { get; set; }

        public List<ProductAttributeValue> Values { get; set; }

        public object[] GetKeys()
        {
            return new object[] {ProductId, AttributeId};
        }
    }

    public class Product
    {
        public Guid Id { get; set; }

        public string Name { get; set; }
    }

    public class Attribute
    {
        public Guid Id { get; set; }

        public string Name { get; set; }
    }

    public class ProductAttributeValue
    {
        public Guid Id { get; set; }

        public string Name { get; set; }
    }

В исходном случае Product и Attribute являются AggregateRoot, поэтому я хочу пропустить навигацию по ссылкам на свойства.Значение - это простая сущность, но мне нужно это как ссылка на список в моем классе ProductAttribute, как вы видите, у этого класса есть составной ключ.Но я хочу, чтобы между ProductAttribute и ProductAttributeValue были установлены обязательные отношения с каскадным удалением.

Этот проект является внешним модулем, поэтому мои текущие конфигурации API являются расширением, которое вызывается в целевом приложении DbContext OnModelCreating.Я должен настроить все свойства и ссылки, которые еще не работали.

        builder.Entity<ProductAttribute>(b =>
        {
            b.ToTable("ProductAttributes");

            b.HasKey(x => new {x.ProductId, x.AttributeId});

            //I should config ProductAttributeValue one-to-many manually here
        }

        builder.Entity<Product>(b =>
        {
            b.ToTable("Products");

            b.HasKey(x => x.Id);
        }

        builder.Entity<Attribute>(b =>
        {
            b.ToTable("Attributes");

            b.HasKey(x => x.Id);
        }

        builder.Entity<ProductAttributeValue>(b =>
        {
            b.ToTable("ProductAttributeValues");

            b.HasKey(x => x.Id);

            //I should config ProductAttribute many-to-one manually here
        }

Как вы можете настроить свой Fluent API для сущности ProductAttribute для прохождения этого сценария?

Ответы [ 2 ]

0 голосов
/ 30 января 2019

Чтобы настроить требуемые отношения как необходимые и каскадное удаление, вы можете использовать следующее внутри блока конфигурации объекта ProductAttribute:

b.HasMany(e => e.Values)
    .WithOne()
    .IsRequired();

IsRequired достаточно, поскольку по соглашению каскадное удаление являетсявключен для обязательных и выключен для необязательных отношений.Конечно, вы можете добавить .OnDelete(DeleteBehavior.Cascade), если хотите - это будет избыточно, но не повредит.

Обратите внимание, что отношения должны быть настроены в одном месте.Так что делайте это либо в ProductAttribute, либо в ProductAttributeValue, но никогда в обоих (подвержен ошибкам, может привести к непредвиденным конфликтам или переопределению проблем конфигурации).

Для полноты, вот как вы можете настроить то же самое внутри *Конфигурация 1013 * (требуется явное предоставление аргумента универсального типа HasOne из-за отсутствия свойства навигации):

b.HasOne<ProductAttribute>()
    .WithMany(e => e.Values)
    .IsRequired();
0 голосов
/ 30 января 2019

Напишите вашу ProductAttribute конфигурацию следующим образом:

modelBuilder.Entity<ProductAttribute>(b =>
{
    b.ToTable("ProductAttributes");

    b.HasKey(x => new {x.ProductId, x.AttributeId});

    b.HasMany(pa => pa.Values).WithOne().IsRequired();
});

Но существует проблема читабельности.Это добавит столбцы ProductAttributeProductId и ProductAttributeAttributeId в качестве составного внешнего ключа к таблице ProductAttributeValues для свойства тени .Если вы хотите сделать составной внешний ключ в таблице ProductAttributeValues более читабельным, вы можете обновить класс модели ProductAttributeValue модели следующим образом:

public class ProductAttributeValue
{
    public Guid Id { get; set; }

    public Guid ProductId { get; set; }

    public Guid AttributeId { get; set; }

    public string Name { get; set; }
}

Затем обновите конфигурацию ProductAttribute следующим образом:

modelBuilder.Entity<ProductAttribute>(b =>
{
    b.ToTable("ProductAttributes");

    b.HasKey(x => new {x.ProductId, x.AttributeId});

    b.HasMany(pa => pa.Values).WithOne().HasForeignKey(pa => new {pa.ProductId, pa.AttributeId});
});

Теперь составной внешний ключ в таблице ProductAttributeValues будет сгенерирован как ProductId и AttributeId.

Спасибо.

...