Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity framework 6 code first - one way many to many via annotations

Is it possible to create one-way many-to-many association in entity framework 6 with code first and annotations? Example:

class Currency
{
    public int id { get; set; }
}

class Country
{
    public int id { get; set; }

    // How i can annotate this property to say EF that it is many-to-many
    // and it should create mapping table?
    // I don't need navigation property to Country in Currency class!
    public virtual IList<Currency> currencies { get; set; }
}

On Java + JPA annotations i can implement what i need this way:

@OneToMany
@JoinTable(name = "MAPPING_TABLE", joinColumns = {
    @JoinColumn(name = "THIS_ID", referencedColumnName = "ID")
}, inverseJoinColumns = {
    @JoinColumn(name = "OTHER_ID", referencedColumnName = "ID")
})

so, does EF have equal features?

like image 798
Anton Avatar asked Jun 06 '13 05:06

Anton


1 Answers

You can do this by specifying the relationship explicitly using the Fluent API. Override the OnModelCreating() method of your DbContext class, and in your override specify the details of the mapping table like this:

class MyContext : DbContext
{
    public DbSet<Currency> Currencies { get; set; }
    public DbSet<Country> Countries { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Country>()
            .HasMany(c => c.Currencies)
            .WithMany()                 // Note the empty WithMany()
            .Map(x =>
            {
                x.MapLeftKey("CountryId");
                x.MapRightKey("CurrencyId");
                x.ToTable("CountryCurrencyMapping");
            });

        base.OnModelCreating(modelBuilder);
    }
}

Note that - in my quick test anyway - you will have to Include() the Currencies property when loading the EF object to have the list populated:

            var us = db.Countries
                        .Where(x => x.Name == "United States")
                        .Include(x=>x.Currencies)
                        .First();

EDIT

If you really want to do everything with Data Annotations, and not use Fluent at all, then you can model the join table explicitly as pointed out elsewhere. There are various usability disadvantages of this approach, though, so it seems the Fluent method is the best approach.

class Country
{
    public int Id { get; set; }
    public virtual ICollection<CountryCurrency> CountryCurrencies { get; set; }
}

class Currency
{
    public int Id { get; set; }
}

class CountryCurrency
{
    [Key, Column(Order=0)]
    public virtual int CountryId { get; set; }
    [Key, Column(Order=1)]
    public virtual int CurrencyId { get; set; }

    public virtual Country Country { get; set; }
    public virtual Currency Currency { get; set; }
}
like image 85
Myk Willis Avatar answered Oct 19 '22 08:10

Myk Willis