Home > Enterprise >  How to use Fluent API for creating a simple one-to-many relationship
How to use Fluent API for creating a simple one-to-many relationship

Time:09-23

Let me first give some background: I'm creating an application, which should handle a DB. That DB might evolve (extra tables/columns/constraints might be added, but nothing gets removed, in fact the DB gets more and more elaborated).

I started with a "Database First" approach and as a result, I have created an Entity Framework diagram, with according classes in *.cs files. Two of those files are (only some interesting fields):

Area.cs:

public partial class Area
{
    public Area() {  }

    public string Name { get; set; }
    public int Id { get; set; }
}

Location.cs:

public partial class Location
{
    public Location() { }

    public string Name { get; set; }
    public int Id { get; set; }
    ...
    public Nullable<int> AreaId { get; set; }
}

This is generated from a version of the DB, which does not cover constraints, and now I would like to add a ForeignKeyConstraint to the corresponding Entity Framework model:

  • Location.AreaId is a foreign key towards Area.Id
  • There are many Location objects for one Area object
  • It's the idea to prevent deletion of Area objects, being referred to by Location objects).

I believe this should be done as follows:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Area>().HasKey(t => t.Id);     // Creation of primary key
    modelBuilder.Entity<Location>().HasKey(t => t.Id); // Creation of primary key

    modelBuilder.Entity<Location>().HasRequired(n => n.AreaId)
                                   .WithMany(...)
                                   .HasForeignKey(n => n.AreaId);
    ...

This, obviously, does not work. I'm missing following information:

  1. My "Area.cs" file does not contain a reference to the Location object (as this version of the DB does not contain constraints, this has not been added by the "database first" wizard), should I add this or can I solve my issue without?
  2. What do I need to fill in instead of the ellipsis .WithMany(...)?
  3. Extra question: I'm aware of the ForeignKey directive. Should I replace public Nullable<int> AreaId { get; set; } in "Location.cs" by [ForeignKey("AreaId")], followed by public virtual Area Area { get; set; }?

Edit
Important remark: as "Location.cs" and "Area.cs" are auto-generated, I like to minimise changes in those files.

Next edit
Meanwhile I've updated my "Location.cs" file as follows:

...
// public Nullable<int> AreaId { get; set; }

[ForeignKey("AreaId")]
public Area Area { get; set;}
....

My OnModelCreating() has been changed into:

modelBuilder.Entity<Location>().HasRequired(n => n.Area)
                               .WithMany(...)
                               .HasForeignKey(n => n.Area);

That leaves only the ellipsis problem to be solved.

Another edit
Since it takes such a long time for an answer (even for a comment), I've decided to add following line of source code to my "Area.cs" file:

public virtual ICollection<Location> Locations { get; set; }

I've then filled in the ellipsis as follows:

modelBuilder.Entity<Location>().HasRequired(l => l.Area)
                               .WithMany(a => a.Locations)
                               .HasForeignKey(l => l.Area);

Now just one question: how can I mention that the link between the Area and the Location should be handled by Location.AreaId and Area.Id (I know that Location.AreaId is the foreign key, but how can I know that it refers to Area.Id)?

Thanks in advance

CodePudding user response:

The simple answer to your last question. EF is recognizing that Area.Id is a primary key so connects Location.AreaId to Area.Id

Also, here is a simple guide on how to do it.

  • Related