Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use EF Code First to declare a one-to-many relationship?

I'm trying to define a simple one-to-many relationship between two poco's, using the Entity Framework fluent API.

~ Team ~
public int TeamId { get; set; }
public ICollection<User> TeamMembers { get; set; } // All the team players. Two way nav.
public Player CreatedBy { get; set; } // Which player created this team. One way navigation.
                                      // Optional. Not all players create a team.

~ Player ~
public int PlayerId { get; set; }
public Team Team { get; set; } // The other side of the TeamMembers navigation.

NOTES:

  • A player doesn't have to be in a team. (unassigned/dropped players).
  • A team might have no players (they have all left/quit).

The closest I thought I got was something like this:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Team>()
        .HasOptional(x => x.TeamMembers)
        .WithMany()
        .WillCascadeOnDelete(false);
}

This doesn't work, and I'm not sure how to define the other navs also.

like image 218
Pure.Krome Avatar asked Mar 20 '11 12:03

Pure.Krome


People also ask

How do you code a one to many relationship?

One to Many Relationship (1:M) This is where a row from one table can have multiple matching rows in another table this relationship is defined as a one to many relationship. This type of relationship can be created using Primary key-Foreign key relationship.

How do I use EF code first?

Step 1 − First, create the console application from File → New → Project… Step 2 − Select Windows from the left pane and Console Application from the template pane. Step 3 − Enter EFCodeFirstDemo as the name and select OK. Step 4 − Right-click on your project in the solution explorer and select Manage NuGet Packages…

What is many-to-many relationships in code first approach?

A many-to-many relationship is defined in code by the inclusion of collection properties in each of the entities - The Categories property in the Book class, and the Books property in the Category class: public class Book. { public int BookId { get; set; }

How do you create a many-to-many relationship in EF core?

Many-to-many relationships require a collection navigation property on both sides. They will be discovered by convention like other types of relationships. The way this relationship is implemented in the database is by a join table that contains foreign keys to both Post and Tag .


1 Answers

I think this object model is what you are looking for:

public class Team
{    
    public int TeamId { get; set; }
    public ICollection<Player> TeamMembers { get; set; } 
    public Player CreatedBy { get; set; } 
}

public class Player
{
    public int PlayerId { get; set; }
    public Team Team { get; set; } 
}       

public class Context : DbContext
{
    public DbSet<Player> Players { get; set; }
    public DbSet<Team> Teams { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Player>()
                    .HasOptional(p => p.Team)
                    .WithMany(t => t.TeamMembers)
                    .Map(c => c.MapKey("TeamId"));

        // Or alternatively you could start from the Team object:
        modelBuilder.Entity<Team>()
                    .HasMany(t => t.TeamMembers)
                    .WithOptional(p => p.Team)
                    .Map(c => c.MapKey("TeamId"));
    }
}

BTW, the following fluent API code that you are using is not correct:

...HasOptional(x => x.TeamMembers)

Because TeamMembers is a collection and cannot be used by HasOptional method which always has to be invoked with a single object.

Update - HasRequired vs. HasOptional:

While they both set up an association, they deliver slightly different results and have different requirements:

  • If it's a FK association (the FK property is exposed on the dependent object) then it must be a nullable type when using HasOptional and non-nullable type when using HasRequired or Code First will throw.

  • Code First will automatically switch cascade deletes on when using HasRequired method.

  • The other difference is the EF runtime behavior when it comes to deletion. Consider a scenario where we want to delete the principal object (e.g. Team) while it has a dependent object (e.g. Player) and cascade delete is switched off. With HasOptional EF runtime will silently update the dependent FK column to null while with HasRequired EF will throw and ask you to either explicitly remove the dependent object or relate it to another principal object (If you want to try this you should be aware that in both cases both principal and dependent objects must be already loaded in context so that EF will have a track of them).

like image 50
Morteza Manavi Avatar answered Sep 22 '22 23:09

Morteza Manavi