2017-12-20 23 views
2

의견 기능을 작업 중입니다. 스레드에 주석을 달 수 있습니다. 또한 댓글에 댓글을 쓸 수도 있습니다. 그래서 스레드 주석의 목록을 가지고 있으며, 모든 댓글은 댓글 목록이 : 내가 가진코드 첫 번째 Entity Framework - 주석 기능에 대한 주석, 두 번째 동일한 주석 표시

public class Thread 
{ 
    public int ThreadId { get; set; } 

    public int PostId { get; set; } 

    public virtual List<Comment> Comments { get; set; } 
} 


public class Comment 
{ 
    public int CommentId { get; set; } 

    [MaxLength(280)] 
    public string Content { get; set; } 

    public long time { get; set; } // unix time/epoch time 

    [JsonIgnore] 
    [IgnoreDataMember] 
    public string user_id { get; set; } 
    public virtual CommentUser CommentUser { get; set; } 

    [JsonIgnore] 
    [IgnoreDataMember] 
    public int ThreadId { get; set; } 

    [JsonIgnore] 
    [IgnoreDataMember] 
    public virtual Thread Thread { get; set; } 

    public virtual List<Comment> Comments { get; set; } 

} 

문제는 내가 스레드에 대해 언급 때 그 의견에 대한 언급이다. 총 2 가지 의견.

나는 세 가지 의견이 JSON을 얻을 :

comments db

스레드를 얻는 방법은 매우 간단합니다 :

{ 
    "ThreadId": 3, 
    "Comments": [ 
    { 
     "Comments": [ 
     { 
      "Comments": [], 
      "CommentUser": { 
      "user_id": "123", 
      "nickname": "user", 
      }, 
      "CommentId": 52, 
      "Content": "comment on comment", 
      "time": 1513784459 
     } 
     ], 
     "CommentUser": { 
     "user_id": "123", 
     "nickname": "user", 
     }, 
     "CommentId": 51, 
     "Content": "asdf asdf asd f", 
     "time": 1513784447 
    }, 
    { 
     // THIS COMMENT SHOULD NOT SHOW UP HERE 
     "Comments": [], 
     "CommentUser": { 
     "user_id": "123", 
     "nickname": "user", 
     }, 
     "CommentId": 52, 
     "Content": "comment on comment", 
     "time": 1513784459 
    } 
    ] 
} 

이는 DB가 보이는 두 의견 방법입니다 :

 Thread commentThread = await (from t in db.Thread where t.PostId == tr.postId select t).FirstOrDefaultAsync(); 

     return Json(commentThread); 

나는 어디에서 t 그의 잘못된다. 어떤 도움을 주셔서 감사합니다! Comment 엔티티에 관계없이 수준의 소유자 Thread와 (필수) 직접적인 관계를 가지고 있기 때문에 자신의 의견에 @Ivan & @Olivier 언급으로

+0

"주석에 대한 주석"은 두 번 나타납니다. 왜냐하면 그것은'Thread.Comments'와'Comment.Comments'의 일부이기 때문입니다. 그것은 당신의 모델에서의 정상적인 행동입니다. 모델을 변경하거나 필터를 사용하여 프로젝션 쿼리를 사용하십시오 (나중에 재귀 데이터 모델에 문제가있을 수 있음). –

+0

주석에 대한 주석이'ThreadId = 3'을 가진 스레드에 대한 직접적인 참조를 가지고 있기 때문에 거기에 표시됩니다. 최상위 레벨 주석에만 스레드에 대한 참조가있는 경우에는 발생하지 않습니다. JSON은 중첩 된 주석을 참조 할 수 없으므로 주석을 반복합니다. –

답변

2

이 발생합니다.

기본적으로 linq 쿼리를 수행하면 결과는 CommentsThread 개체가됩니다. 두 번째 댓글은 첫 번째 댓글 댓글에서 볼 수있는 것과 동일한 댓글입니다. 오, 이런, 한마디. 이 같은

뭔가 :이 문제를 방지하기 위해

commentThread.Comments = Comment[] 

    //first comment from thread 
    { 
     "CommentId": 1, 
     "Content": "Thread comment", 

      "Comments": [ 
       //This is the same comment (Id = 2) being fetched from both Thread and Comment entities. 
       { 
        "CommentId": 2, 
        "Content": "Comment on comment" 
       } 
     ] 
    }, 

    //second comment from thread 
    { 
     "CommentId": 2, 
     "Content": "Comment on comment" 
    } 
] 

한 가지 방법은 최고 수준의 코멘트에서 null로 ThreadId 설정된 모든 중첩 된 의견 스레드를 참조 만하는 것입니다. 이렇게하면 검색어가 깨끗하게 유지되므로 최상의 결과를 얻을 수 있습니다. 즉, 필터를 적용하거나 제외하거나 코드를 참조 할 필요가 있는지 여부를 확인할 필요가 없습니다.

그러나 ThreadId가 int이기 때문에 현재 모델에서 허용하지 않습니다. 얼마나 많은 모델을 보여 주 었는지에 따라 상대적으로 쉽게 달성 할 수 있습니다.

public class Comment 
{ 
    public int CommentId { get; set; } 

    [MaxLength(280)] 
    public string Content { get; set; } 

    public long time { get; set; } // unix time/epoch time 

    [JsonIgnore] 
    [IgnoreDataMember] 
    public string user_id { get; set; } 
    public virtual CommentUser CommentUser { get; set; } 

    [JsonIgnore] 
    [IgnoreDataMember] 
    public int? ThreadId { get; set; } 
      ^//set this as nullable 

    [JsonIgnore] 
    [IgnoreDataMember] 
    public virtual Thread Thread { get; set; } 

    public virtual List<Comment> Comments { get; set; } 

} 

이 마이그레이션을 실행하고 DB를 업데이트 (또는 DBA를위한 스크립트를 얻을) :

추가 마이그레이션 SetThreadIdAsNullable

update- 그러니 그냥 재산 ThreadIdint?로 설정 데이터베이스 또는 업데이트 데이터베이스 - 스크립트

그리고 잘 가야합니다. 이제 쿼리는 comment이 하나만있는 thread 개체를 반환해야합니다.이 개체는 달성하려는대로 중첩 된 comment을 포함해야합니다.

희망이 도움이됩니다.

+1

많은 도움이되었습니다! 정말 고맙습니다. 그것은 내 문제를 해결 :) – ganjan

1

엔티티의 일반적인 동작은 Thread입니다. 왜냐하면 주석 표에는 ThreadId = 3이라는 두 개의 레코드가 있기 때문입니다. 따라서, Comment_CommentId이 null이 아닌 주석 레코드를 제거해야합니다. 그래서, 아마 확장 메서드를 사용하여 필터링 할 수 있습니다;

public static class ThreadExtensions 
{ 
    public static IQueryable<Thread> GetThreadAsQueryable(this DbSet<Thread> table) 
    { 
     return table.Where(x => x.Comments.Where(x => x.Comment_CommentId == null)); 
    } 
} 

using (var context = new SampleDbContext()) 
{ 
    var str = context.Thread.GetThreadAsQueryable().ToList(); 
} 

또한, EfCore 2.0 에 대한 HasQueryFilter라는 기능이 있습니다. 제 생각에, 그것은 그것이 필요로하는 것을 정확히 만족시킵니다. EfCore 2.0을 사용하는 경우 it을 확인하는 것이 좋습니다.