开发者

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

开发者 https://www.devze.com 2023-02-18 18:35 出处:网络
I\'m trying to define a simple one-to-many relationship between two poco\'s, using the Entity Framework fluent API.

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).
  • 开发者_JS百科
  • 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.


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).


I've been able to get this to work automatically simply by doing something like this:

 public class Team {
    public int TeamId { get; set; }
    ...
    public virtual ICollection<Player> Players { get; set; }
}

But you'll have to be more specifical about what exactly you mean when you say "doesn't work". What doesn't work, exactly? Are you getting an error message? If so, what is it? Is the Team property of the Player object always returning null?

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号