1

I have an entity, Post:

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

I have another entity, Response:

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

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

The idea is, a Response either has a ParentResponseId defined, OR a PostId - but never both. A Post can have many Responses, and a Response can have many Responses.

I never need to navigate from one to the other via virtual properties, nor do I need lazy loading - I just need the constraints set up in the db.

I'm new to modelBuilder but this seems like a case where it would have to be used. I have a starting point:

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

Is this the correct way to handle an optional one-to-many? Is there any way to add a constraint that says "one or the other FK needs to be defined"? Any guidance here would be much appreciated.

4

2 回答 2

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()从您的模型构建器块中删除调用。

希望这可以帮助

于 2013-11-12T13:46:57.143 回答
0

您可以继承ReponsePost只有一个外键,因此您永远不必担心应该设置哪个 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

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

于 2013-11-12T08:44:48.490 回答