问题
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