Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Foreign key with composite key in EF Core

I have the following classes:

    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; }
    }

In origin case Product and Attribute are AggregateRoot so I want skip navigate that by property references. Value is a simple entity but I need that as list reference in my ProductAttribute class as you see that class have composite key. But I want a required relationship with cascade delete between ProductAttribute and ProductAttributeValue.

This project is external module, so my fluent API configurations are extension which called in target app DbContext OnModelCreating. I should config every properties and references else didn't work.

        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
        }

How can you configure your Fluent API for ProductAttribute entity to passing this scenario?

like image 260
hitasp Avatar asked Jan 30 '19 13:01

hitasp


People also ask

Can a foreign key be a composite key?

A composite foreign key is a foreign key that consists of two or more columns. It is important to note that all the columns in a single foreign key must point to the same table. In other words, it is not possible to have a foreign key that references to a column in Table 1 and a column in Table 2.

How do you create a composite primary key in EF core?

The only way to configure composite keys is to use the HasKey method. You specify the properties that form the composite key by passing them in as properties of an anonymous type to the HasKey method.

How do you add a foreign key to EF?

The [ForeignKey(name)] attribute can be applied in three ways: [ForeignKey(NavigationPropertyName)] on the foreign key scalar property in the dependent entity. [ForeignKey(ForeignKeyPropertyName)] on the related reference navigation property in the dependent entity.


1 Answers

Write your ProductAttribute configuration as follows:

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

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

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

But there is a concern of readability. This will add the columns ProductAttributeProductId and ProductAttributeAttributeId as composite foreign key to the table ProductAttributeValues for the shadow property. If you want to make composite foreign key in table ProductAttributeValues more readable then you can update your model ProductAttributeValue model class as follows:

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

    public Guid ProductId { get; set; }

    public Guid AttributeId { get; set; }

    public string Name { get; set; }
}

Then update the ProductAttribute configuration as follows:

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});
});

Now composite foreign key in table ProductAttributeValues will be generated as ProductId and AttributeId.

Thank you.

like image 196
TanvirArjel Avatar answered Oct 23 '22 02:10

TanvirArjel