Προσθέτοντας ένα σχόλιο Μέρος Συστήματος 1 ΜSK1 Ρυθμίστε τη βάση δεδομένων (ελληνικά (Greek))

Προσθέτοντας ένα σχόλιο Μέρος Συστήματος 1 ΜSK1 Ρυθμίστε τη βάση δεδομένων

Monday, 26 August 2024

//

7 minute read

Εισαγωγή

Μία από τις βασικές πτυχές ενός ιστοτόπου blogging όπως αυτό είναι ένα σύστημα σχολίων. ΈτσιΜSK1 αποφάσισα να χτίσω ένα. Αυτό είναι το πρώτο μέρος μιας σειράς δημοσιεύσεων σχετικά με το πώς να χτιστεί ένα σύστημα σχόλισηςM SK3 Σε αυτή την ανάρτησηMSKA4 θα δημιουργήσω τη βάση δεδομένωνMKA5

Δημιουργία της βάσης δεδομένων

Όπως με το υπόλοιπο της ιστοσελίδας που μου άρεσε'μ χρησιμοποιώντας Postgres για τα blogs;μ να ξεκινήσει με ΕμέναΜSK2μ με χρήση αναδρομικών ερωτήσεων για την αποθήκευση των σχολίων ΜSK3μ δεν μου αρέσει αυτό έντονα,μ αλλά μας παίρνει έξω από την πόρτα με ένα σύστημα σχόλισης M SK5μ και δεν θα ελπίζω'μ έχουν πολύ κίνησηMSKA7μ έτσι ώστε να ελπίζει'μ όχι μια μεγάλη συμφωνίαΜΣΚ9μμ'μ θα μετακινηθεί σε ένα πιο αποτελεσματικό σύστημα στο μέλλονΜСК11μ

Το πλαίσιο της ΕΦ

Στο τρέχον σύστημα χρησιμοποιούμε ένα 'Comment Closure' για να καθορίσουμε τις σχέσεις μεταξύ των σχολίων ΜSK2 έτσι μπορώ να υποστηρίζω τα σχόλιά σαςM SK3Το διάγραμμα της τάξης μας μοιάζει με αυτό

classDiagram
    class CommentEntity {
        int Id
        CommentStatus Status
        string Author
        string? HtmlContent
        string Content
        DateTime CreatedAt
        int PostId
        int? ParentCommentId
    }

    class BlogPostEntity {
        int Id
        string Title
        string Content
        DateTime CreatedAt
    }

    class CommentClosure {
        int AncestorId
        int DescendantId
        int Depth
    }

    CommentEntity "1" --> "1" BlogPostEntity : belongs to
    CommentEntity "1" --> "0..1" CommentEntity : parent
    CommentEntity "0..*" --> "0..*" CommentClosure : Ancestors
    CommentEntity "0..*" --> "0..*" CommentClosure : Descendants
    CommentClosure "1" --> "1" CommentEntity : Ancestor
    CommentClosure "1" --> "1" CommentEntity : Descendant

    class CommentStatus {
        <<enum>>
        Pending
        Approved
        Rejected
        Deleted
    }

Μπορείτε να δείτε εδώ ότι κάθε CommentEntity Έχει μια PostId για το post που ανέφερε' αναφέρει συνδεδεμένο με, αναφέρουν και ένα ParentCommentId για το σχόλιο που ανέφερε' ανέφερε συνδεδεμένο με ( ανέφερε οποιοδήποτε ερώτημα). ανέφερε CommentClosure Ο πίνακας χρησιμοποιείται για να αποθηκεύσει τις σχέσεις μεταξύ των σχολίων.

Η υπηρεσία σχολίων

Η CommentService είναι υπεύθυνος για τη διαχείριση σχολίων. Έχει μεθόδους για την προσθήκη ειδών, έγκρισης ειδώνΜSK2 απόρριψης ειδών ΜSK3 και διαγραφής σχολίων ειδών . Υπάρχουν επίσης μέθοδοι για να λάβει σχόλια για ένα post ειδών

Η διεπαφή μας για αυτή την υπηρεσία μοιάζει με αυτό:

public interface ICommentService
{
    Task<string> Add( int postId, int? parentCommentId, string author, string content);
    Task<List<CommentEntity>> GetForPost(int blogPostId, int page = 1, int pageSize = 10, int? maxDepth = null, CommentStatus? status = null);
    Task<List<CommentEntity>> GetDescendants(int commentId, int maxDepth = 0);

     Task<CommentEntity> Get(int commentId);
    Task<List<CommentEntity>> GetAncestors(int commentId);
    Task Delete(int commentId);
    Task Reject(int commentId);
    Task Approve(int commentId);
}

Η προσθήκη μέθοδος

Η μέθοδος Προσθήκης μας συγκεντρώνει τη δομή αυτού του συστήματος σχολίων.

Πρώτα ξεκινά μια νέα συναλλαγή; για αυτές τις μη εξοικειωμένες συναλλαγές είναι ένας τρόπος να διασφαλιστεί ότι μια ομάδα των συναλλαγών αντιμετωπίζονται ως μία μονάδα εργασίαςΜSK1 Εάν οποιαδήποτε από τις συναλλαγες αποτύχει ΜSK2 η συναλλαγής μπορεί να περιστρέφεται πίσω ΜΣΚ3 και όλες οι αλλαγές είναι άκυρες . Αυτό είναι σημαντικό όταν έχετε πολλαπλές εργασίες που πρέπει να γίνουν μαζί ΜСК5 και θέλετε να βεβαιωθείτε ότι όλα επιτυγχάνουν ή αποτυγχάνονται μαζί

Στη συνέχεια διαχωρίζει το κείμενο των σχολίων από Markdown στο HTML χρησιμοποιώντας τη βιβλιοθήκη Markdig.Αυτό είναι ένας απλός τρόπος για να επιτρέψει στους χρήστες να μορφοποιήσουν τα σχόλιά τους χρησιμοποιώντας Markdown.

Στη συνέχεια δημιουργεί την οντότητα και αποθηκεύει ότι στη βάση δεδομένων.

Αυτό γίνεται σε δύο βήματα - σίγουρα πρώτα το σχόλιο αποθηκεύεταιΜSK1 σίγουρα στη συνέχεια το κλείσιμο του σχόλιου αποθηκευτεί ΜSK2 σίγουρα Αυτό είναι επειδή το σχήμα πρέπει να διατηρηθεί για να δημιουργηθεί το ID ΜΚ3 σίγουρα που χρησιμοποιείται στο κλείσιμο ΜΣ4 σίγουρα

Ακολουθεί η ιεραρχία της CommentClosures που καθορίζει τις σχέσεις μεταξύ των σχολίων. Ξεκινάμε με ένα εαυτόΜSK1αναφοράς κλείσιμο εισαγωγή, τότε αν υπάρχει γονικό σχόλιο συλλέγουμε όλους τους προγόνους του γονικού σχόλου και τα προσθέτουμε στο νέο σχόλιόM SK3 Στη συνέχεια προσθέτοντας έναν άμεσο γονέαMK4συγγενή σχέσηMKK5

Τέλος, το , θα αναλάβουμε τη συναλλαγή το . θα αναλαμβάνουμε Αν οποιαδήποτε από τις συναλλαγές αποτύχει η , θα ανακτήσει την συναλλαγία

 public async Task<string> Add(int postId, int? parentCommentId, string author, string content)
  {
      await using var transaction = await context.Database.BeginTransactionAsync();
      try
      {
         var html = Markdig.Markdown.ToHtml(content);
          // Create the new comment
          var newComment = new CommentEntity()
          {
              HtmlContent = html,
              Content = content,
              CreatedAt = DateTime.UtcNow,
              PostId = postId,
              Author = author,
              Status = CommentStatus.Pending,
              ParentCommentId = parentCommentId
          };
            
          context.Comments.Add(newComment);
          await context.SaveChangesAsync();
          logger.LogInformation("Saved comment to DB");// Save to generate the new comment's Id

          // Insert into CommentClosure table
          var commentClosures = new List<CommentClosure>();

          // Self-referencing closure entry
          commentClosures.Add(new CommentClosure
          {
              AncestorId = newComment.Id,
              DescendantId = newComment.Id,
              Depth = 0
          });

          // If there is a parent comment, insert the ancestor relationships
          if (parentCommentId.HasValue)
          {
              // Fetch all ancestors of the parent comment
              var parentAncestors = await context.CommentClosures
                  .Where(cc => cc.DescendantId == parentCommentId.Value)
                  .ToListAsync();

              // Add ancestor relationships for the new comment
              foreach (var ancestor in parentAncestors)
              {
                  commentClosures.Add(new CommentClosure
                  {
                      AncestorId = ancestor.AncestorId,
                      DescendantId = newComment.Id,
                      Depth = ancestor.Depth + 1
                  });
              }

              // Add a direct parent-child relationship
              commentClosures.Add(new CommentClosure
              {
                  AncestorId = parentCommentId.Value,
                  DescendantId = newComment.Id,
                  Depth = 1
              });
          }

          context.CommentClosures.AddRange(commentClosures);
          await context.SaveChangesAsync();
          logger.LogInformation("Saved comment closure to DB");

          // Commit transaction
          await transaction.CommitAsync();
          return html;
      }
      catch (Exception e)
      {
          // Rollback transaction in case of failure
          await transaction.RollbackAsync();
          logger.LogError(e, "Failed to save comment to DB");
      }

      return string.Empty;
  }

Η μέθοδος GetForPost

Έχουμε κερδίσει το ' θα καλύψει όλο το πράγμα, αλλά Add και Get είναι οι κύριες λειτουργίες CRUD μας για αυτή την υπηρεσία. επιχειρήσεις

Όπως μπορείτε να δείτε έχουμε σελίδες με βάση το σχόλιο κορυφαίου επιπέδου.Έχουμε επίσης ένα maxDepth παράμετρος που μας επιτρέπει να περιορίσουμε το βάθος του δέντρου σχολίων.Αυτό είναι χρήσιμο αν θέλουμε μόνο να δείξουμε τα κορυφαίαΜSK1 ανακοινώσεις σχόλια, ή εάν θέλουμε να περιοριστούμε το βάθρο του δένδρου για τη βελτίωση της απόδοσηςM SK3

Με αυτή την επανειλημμένη προσέγγιση πρέπει να εφαρμόσουμε το φίλτρο βάθους μετά από αυτό που γνωρίζουμε' αναφέρει κρεμασμένα τα σχόλια, αναφέρει καθώς μπορούμε να γνωρίσουμε' αναφέρει το κάνει στο ερώτημα. αναφέρει Αυτό είναι επειδή το βάθος ενός σχόλιου καθορίζεται από τον αριθμό των προγόνων έχει γνωρίσει, αναφέρει και μπορεί να γνωρίζει' αναφέρει εύκολα αναρωτιέται σε SQL αναφέρει. αναφέρει

  public async Task<List<CommentEntity>> GetForPost(int blogPostId, int page = 1, int pageSize = 10, int? maxDepth = null, CommentStatus? status = null)
  {
      // Step 1: Query the top-level comments for the specified blog post
      var query = context.Comments
          .Where(c => c.PostId == blogPostId)
          .OrderByDescending(c => c.CreatedAt)
          .Skip((page - 1) * pageSize)
          .Take(pageSize);

      // Step 2: Filter by status if provided
      if (status.HasValue)
      {
          query = query.Where(c => c.Status == status.Value);
      }

      var topLevelComments = await query
          .Include(c => c.ParentComment)
          .Include(d=>d.Descendants)
          .ToListAsync();

      // Step 4: Filter descendants based on the maxDepth
      foreach (var comment in topLevelComments)
      {
          if (maxDepth != null)
          {
              FilterDescendantsByDepth(comment, 0, maxDepth.Value);
          }
      }

      return topLevelComments;
  }

// Recursive helper method to limit the descendants based on the specified depth
  private void FilterDescendantsByDepth(CommentEntity comment, int currentDepth, int maxDepth)
  {
      if (currentDepth >= maxDepth)
      {
          // If the max depth is reached or there are no descendants, stop recursion
          comment.Descendants = new List<CommentClosure>();  // Clear further descendants beyond maxDepth
          return;
      }

      foreach (var closure in comment.Descendants.ToList())  // Iterate over a copy to prevent modification during iteration
      {
          FilterDescendantsByDepth(closure.Descendant, currentDepth + 1, maxDepth);
      }
  }

Στο συμπέρασμα

Αυτό είναι ένα απλό σύστημα σχόλισης που χρησιμοποιεί επαναλαμβανόμενες ερωτήσεις για να αποθηκεύσει τις σχέσεις μεταξύ των σχολίων.ΑυτόΜSK1 δεν διατηρεί το πιο αποτελεσματικό σύστημα, αλλά αυτόMK3 διατηρείται απλή και λειτουργείM SK4Στο μέλλονMSKA5Αυτή η ' αναμένεται να καλύψει τα μπροστινά σημεία αυτού του συστήματοςΗ ; αναμένει πολλά από HTMXΟ ,Ο AlpineΟ ΜSK9 υποστηρίζειΗ ΜSK10ο Tailwind CSS

Μέχρι τότε οι επιχειρήσεις , αισθάνονται ελεύθεροι να αφήσουν ένα σχόλιο κάτω από τις επιχειρήσεις !

Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.