使用ModelBuilder定义可选的一对多自引用关系?

时间:2013-11-12 03:05:52

标签: entity-framework ef-code-first ef-migrations

我有一个实体,帖子:

 public class Post
 {
    [Key]
    [Required]
    public int PostId { get; set; }
 }

我有另一个实体,Response

 public class Response
 {
    [Key]
    [Required]
    public int ResponseId{ get; set; }

    public int PostId {get; set;}
    public int ParentResponseId {get; set;}
 }

这个想法是,Response要么定义了ParentResponseId,要么PostId - 但不是两者都有。 Post可以有很多回复,Response可以有很多回复。

我永远不需要通过virtual属性从一个导航到另一个,也不需要延迟加载 - 我只需要在数据库中设置约束。

我是modelBuilder的新手,但这似乎是必须使用它的情况。我有一个起点:

  modelBuilder.Entity<Response>()
        .HasOptional(c => c.Post)
        .HasForeignKey(u => u.PostId);
  modelBuilder.Entity<Response>()
        .HasOptional(c => c.Response)
        .HasForeignKey(u => u.ParentResponseId);

这是处理可选的一对多的正确方法吗?有没有办法添加一个约束,说“需要定义一个或另一个FK”?这里的任何指导都将非常感激。

2 个答案:

答案 0 :(得分:1)

您现在需要有4个班级

public class Post
{
  [Key]
  [Required]
  public int PostId { get; set; }

  public virtual ICollection<PostResponse> Responses { get; set; }
}

public abstract class Response //abstract to never get just a simple response
{
  [Key]
  [Required]
  public int ResponseId{ get; set; }

  public string Message { get; set; }
}

public class PostResponse : Response
{
  [Required]
  public int PostId { get; set; }

  public Post Post { get; set; }
}

public class ResponseReply : Response
{
  [Required]
  public int ParentResponseId { get; set; }

  public virtual Response ParentResponse { get; set; }
}

在您的ModelBuilder块中:

modelBuilder.Entity<PostResponse>()
            .ToTable("PostResponse")
            .HasRequired(c => c.Post)
            .WithMany(c => c.Responses)
            .HasForeignKey(u => u.PostId);
modelBuilder.Entity<ResponseReply>()
            .ToTable("ResponseReply")
            .HasRequired(c => c.ParentResponse)
            .WithMany()
            .HasForeignKey(u => u.ParentResponseId);

这将为您创建3个表,以便处理模型中的响应想法。 这有助于您强制实际需要PostId和ParentResponseId,并在单独的表中创建 "NOT NULL" 列。

如果您不想要单独的表并将外键保留为数据库中的可选项,只需从模型构建器块中删除 ToTable() 调用。

希望这会有所帮助

答案 1 :(得分:0)

您可以从Reponse继承Post并且只有一个外键,因此您永远不必担心应该设置哪个FK:

public class Post
{
    public int PostId { get; set; }
    public Post ParentPost { get; set; }
    public int? ParentPostId { get; set; }
}

public class Response : Post
{
}

使用映射:

modelBuilder.Entity<Post>()
            .HasOptional(p => p.ParentPost)
            .WithMany()
            .HasForeignKey(p => p.ParentPostId);

现在,如果你这样做

var a = new Post();
var b = new Response { ParentPost = a };
var c = new Response { ParentPost = b };
db.Posts.Add(c);
db.SaveChanges();

你会得到

PostId      ParentPostId Discriminator
----------- ------------ -------------
1           NULL         Post
2           1            Response
3           2            Response

如果帖子和回复本质上是不同的东西,也许这不起作用,但我很难想象是这样的。