如何使用EF Code First声明一对多关系?

时间:2011-03-20 12:47:37

标签: c# .net entity-framework

我正在尝试使用Entity Framework流畅的API在两个poco的之间定义一个简单的一对多关系。

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

注意:

  • 玩家不必在团队中。 (未分配/弃牌)。
  • 一个团队可能没有玩家(他们都已离开/退出)。

我认为最接近的是这样的......

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

...哪个不起作用..而且我也不确定如何定义其他导航。

有人可以帮忙吗?

2 个答案:

答案 0 :(得分:12)

我认为这个对象模型正是您所寻找的:

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,您使用的以下流畅的API代码不正确:

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

因为TeamMembers是一个集合,并且 HasOptional 方法不能使用它,它总是必须用一个对象调用。

更新 - HasRequired与HasOptional:

虽然他们都建立了一个关联,但他们提供的结果略有不同,并且有不同的要求:

  • 如果它是FK关联(FK属性在依赖对象上公开),那么在使用 HasOptional 时它必须是可空类型,而在使用 HasRequired时它是非可空类型或Code First将抛出。

  • 使用 HasRequired 方法时,Code First会自动切换级联删除。

  • 另一个区别是删除时的EF运行时行为。考虑我们想要删除主要对象(例如Team)同时它具有依赖对象(例如Player)并且关闭级联删除的情况。使用 HasOptional EF运行时将静默地将依赖的FK列更新为null,而使用 HasRequired EF将抛出并要求您显式删除依赖对象或将其与另一个主体对象关联(如果你想尝试这个,你应该知道,在这两种情况下,主要和从属对象必须已经在上下文中加载,以便EF将跟踪它们。)

答案 1 :(得分:2)

通过这样做,我已经能够自动完成这项工作:

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

但是当你说“不起作用”时,你必须更明确地指出你究竟是什么意思。究竟什么不起作用?您收到错误消息了吗?如果是这样,它是什么? Player对象的Team属性是否始终返回null?