Setup one to many relation with fk having multiple rows

不羁的心 提交于 2020-01-24 13:55:52

问题


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:

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.


回答1:


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.

P.S. Appreciate adding the sample project




回答2:


    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




回答3:


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.



来源:https://stackoverflow.com/questions/58914671/setup-one-to-many-relation-with-fk-having-multiple-rows

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!