简体   繁体   中英

Setup one to many relation with fk having multiple rows

I have a problem with setting up a one-to-many relation with EF Core.
I have two tables address and address_country . There are schemas: 地址表模式
address_country 表架构
As you see, I want to store countries with different locales. So it has a composed key. address table has a foreign key to address_country . Unfortunately, I cannot setup ContextDb to achieve what I want. The list of countries is not filled in Address model.
I have the following code in Context :

public class Context : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite(
            @"Data Source=addresses.db");
        base.OnConfiguring(optionsBuilder);
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<AddressDto>()
            .ToTable("address");

        modelBuilder.Entity<CountryLocaleDto>()
            .ToTable("address_country");

        modelBuilder.Entity<CountryLocaleDto>()
            .HasKey(cl => new {cl.Id, cl.Locale});

        base.OnModelCreating(modelBuilder);
    }

    public DbSet<AddressDto> Addresses { get; set; }
}

And my models are

public class AddressDto
{
    public int Id { get; set; }
    public int CountryId { get; set; }
    public List<CountryLocaleDto> CountryLocale { get; set; }
}
public class CountryLocaleDto
{
    public int Id { get; set; }
    public string Locale { get; set; }
}

There is no exception. I simply don't know how to configure this kind of relation. Can anyone help me with that, please?
Example data would be:
address (id, countryId)
(1, 1)
(2, 1)
address_country (id, locale, name)
(1, 'en', 'Germany')
(1, 'de', 'Deutschland')
An example solution with SQLite db can be found with this link .

If I got you right - you just need to add this code to your context class

modelBuilder.Entity<AddressDto>()
            .HasMany(e=>e.CountryLocale)
            .WithOne()
            .HasForeignKey(x=>x.Id)
            .HasPrincipalKey(x=>x.CountryId);

Here you have to add HasForeignKey and HasPrincipalKey

The Entity Framework Core Fluent API HasForeignKey method is used to specify which property is the foreign key in a relationship.

Principal key : The property(s) that uniquely identifies the principal entity. This may be the primary key or an alternate key. Navigation property : A property defined on the principal and/or dependent entity that contains a reference(s) to the related entity(s).

your model should look like that

public class AddressDto
{
    public int Id { get; set; }
    public int CountryId { get; set; }
    public List<CountryLocaleDto> CountryLocale { get; set; }
}
public class CountryLocaleDto
{
    public int Id { get; set; }
    public string Locale { get; set; }
}

I mean you don't have to add anything else in your model.

I hope it was helpful.

PS Appreciate adding the sample project

I can see your problem now. If address has a foreign key to address_country , then that means that One AddressDto can have only One CountryLocaleDto . If you want one address to connect to mane address_country , then in your address_country you should have a foreign key to address

If you want to have a Many to Many relationship, then you need an intermediary table the address_country_address

If you go with the first solution, then you can add the AddressId column in your address_country and extend your CountryLocaleDto like this:

public class CountryLocaleDto
{
    public int Id { get; set; }
    public string Locale { get; set; }
    public int AddressId {get; set;}
}

Then do the following?

modelBuilder.Entity<AddressDto>()
    .HasMany(c => c.CountryLocaleDto)
    .WithOne(a => a.AddressDto);
    .HasForeignKey(a => a.CountryId);
    .HasPrincipalKey(c => c.Id);

That is generally the way we declare the one Address to Many CountryLocale.

Edit

After the comments, we figured out that there is a CountryId column in the address table.

Since we need to change the Principal key from one to the other, then we need to use the alternate keys solution from microsoft.

Relationships that are discovered by convention will always target the primary key of the principal entity. To target an alternate key, additional configuration must be performed using the Fluent API.

    public class AddressDto
    {
        public int Id { get; set; }
        public int CountryId { get; set; }
        public List<CountryLocaleDto> CountryLocale { get; set; }
    }
    public class CountryLocaleDto
    {
        public int Id { get; set; }
        public string Locale { get; set; }
        public int AddressDtoId {get; set;}
        public AddressDto Address {get; set;}
    }

   modelBuilder.Entity<CountryLocaleDto>()
                .HasOne(p => p.Address)
                .WithMany(b => b.CountryLocale);

This should configure the relationship of one to many, with one address to many countries.

Source for this would be: https://docs.microsoft.com/en-us/ef/core/modeling/relationships#fluent-api

As well you can do something like this and remove the AddressDto property from CountryLocaleDto:

            modelBuilder.Entity<CountryLocaleDto>(model =>
            {
                model.HasOne<AddressDto>()
                      .WithMany()
                      .HasForeignKey(x => x.AddressDtoId);
            });

UPDATE:

modelBuilder.Entity<AddressDto>()
                .HasMany(b => b.CountryLocale)
                .WithOne();

public class AddressDto
        {
            public int Id { get; set; }
            public int CountryId { get; set; }
            public List<CountryLocaleDto> CountryLocale { get; set; }
        }
        public class CountryLocaleDto
        {
            public int Id { get; set; }
            public string Locale { get; set; }
        }

Soure:https://docs.microsoft.com/en-us/ef/core/modeling/relationships - Single navigation Property

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM