Skip to content

feat : Fix for migration and course final#90

Merged
KietPham-VN merged 1 commit into
mainfrom
feat/fix-for-update-db
Jun 3, 2026
Merged

feat : Fix for migration and course final#90
KietPham-VN merged 1 commit into
mainfrom
feat/fix-for-update-db

Conversation

@EricN2907

@EricN2907 EricN2907 commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Bug Fixes
    • Curriculum section content is now modifiable, allowing updates to stored content data.
    • Enhanced JSON serialization and deserialization support for curriculum sections.

@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The CurriculumSection domain entity's Content property contract shifts from IReadOnlyList<string> to List<string>. JSON deserialization support is introduced via a [JsonConstructor] attribute on the parameterless constructor. The public constructor now directly assigns the mutable list instead of converting to read-only.

Changes

CurriculumSection Entity Mutation and JSON Support

Layer / File(s) Summary
CurriculumSection content property and JSON constructor
backend/Src/PIED_LMS.Domain/Entities/CurriculumSection.cs
Content property type changes from IReadOnlyList<string> to List<string>. System.Text.Json.Serialization namespace is added. [JsonConstructor] attribute marks the private parameterless constructor for JSON instantiation. Public constructor directly creates a List<string> instead of converting to read-only via AsReadOnly().

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

A list once locked, now flows free,
From read-only chains to mutability,
JSON whispers through the constructor's door,
Content morphs—immutable no more. 📋✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'feat : Fix for migration and course final' is vague and does not clearly describe the actual changes made to the codebase. Replace with a precise, descriptive title reflecting the actual change, such as 'Change CurriculumSection.Content from IReadOnlyList to mutable List' or 'Make CurriculumSection.Content mutable for JSON deserialization'.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/fix-for-update-db

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/Src/PIED_LMS.Domain/Entities/CurriculumSection.cs (1)

22-29: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Fix: domain validation is executed during JSON deserialization and can break course reads.

backend/Src/PIED_LMS.Domain/Entities/CurriculumSection.cs puts [JsonConstructor] on the constructor that enforces invariants via ArgumentException when Title, Summary, or Content are empty/whitespace (lines 19-34). backend/Src/PIED_LMS.Persistence/Configurations/CourseConfiguration.cs then deserializes Course.Curriculum during EF materialization with no exception handling (lines 58-65):

  • Any persisted curriculum section with empty/all-whitespace Content (or empty Title/Summary) will throw during deserialization, causing the read to fail for that row—and typically aborts the entire course query/request.

Move/soften this validation at the persistence boundary (e.g., custom JSON converter / try-catch in the converter that maps invalid items to a safe default), or run a DB migration/sanitization to guarantee no legacy/external JSON can violate these invariants before merging.

// CurriculumSection.cs (current state)
if (string.IsNullOrWhiteSpace(title))
    throw new ArgumentException("Curriculum section must have a title.");

if (string.IsNullOrWhiteSpace(summary))
    throw new ArgumentException("Curriculum section must have a summary.");

if (content == null || content.Count == 0 || content.All(string.IsNullOrWhiteSpace))
    throw new ArgumentException("Curriculum section must have at least one valid content item.");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/Src/PIED_LMS.Domain/Entities/CurriculumSection.cs` around lines 22 -
29, The JsonConstructor on CurriculumSection currently throws ArgumentException
for invalid title/summary/content (checks on title, summary, content) which
causes EF materialization in CourseConfiguration when deserializing
Course.Curriculum to fail; instead, remove or relax strict validation from the
JsonConstructor and push strict invariant checks into domain factory/validation
methods used at write-time, or implement a custom JsonConverter used by the
persistence layer that wraps deserialization of CurriculumSection and on error
(or when content/title/summary are empty) maps to a safe default instance or
sanitizes values (e.g., empty strings -> null/empty allowed, content -> empty
list) so reads never throw during EF materialization; update CourseConfiguration
to use that converter or catch deserialization errors and substitute a safe
fallback.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/Src/PIED_LMS.Domain/Entities/CurriculumSection.cs`:
- Line 9: CurriculumSection exposes a mutable List<string> via the Content
property which breaks encapsulation and conflicts with System.Text.Json
constructor binding; change the property signature from List<string> to
IReadOnlyList<string> and update the [JsonConstructor] parameter on the
CurriculumSection constructor to also accept IReadOnlyList<string>, then store a
defensive copy into a private List<string> backing field (e.g., _content) and
have the public Content return the IReadOnlyList view (or the backing field as
IReadOnlyList) so deserialization types match and consumers cannot mutate the
internal list.

---

Outside diff comments:
In `@backend/Src/PIED_LMS.Domain/Entities/CurriculumSection.cs`:
- Around line 22-29: The JsonConstructor on CurriculumSection currently throws
ArgumentException for invalid title/summary/content (checks on title, summary,
content) which causes EF materialization in CourseConfiguration when
deserializing Course.Curriculum to fail; instead, remove or relax strict
validation from the JsonConstructor and push strict invariant checks into domain
factory/validation methods used at write-time, or implement a custom
JsonConverter used by the persistence layer that wraps deserialization of
CurriculumSection and on error (or when content/title/summary are empty) maps to
a safe default instance or sanitizes values (e.g., empty strings -> null/empty
allowed, content -> empty list) so reads never throw during EF materialization;
update CourseConfiguration to use that converter or catch deserialization errors
and substitute a safe fallback.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d7f8e37d-c3c6-4853-b822-3c32f00b9694

📥 Commits

Reviewing files that changed from the base of the PR and between f4b666d and e2c15a9.

⛔ Files ignored due to path filters (2)
  • backend/Src/PIED_LMS.Persistence/Migrations/20260603020622_AddMaxCapacityAndCurrentEnrollment.Designer.cs is excluded by !**/*.Designer.cs, !**/Migrations/** and included by backend/Src/**
  • backend/Src/PIED_LMS.Persistence/Migrations/20260603020622_AddMaxCapacityAndCurrentEnrollment.cs is excluded by !**/Migrations/** and included by backend/Src/**
📒 Files selected for processing (1)
  • backend/Src/PIED_LMS.Domain/Entities/CurriculumSection.cs

public string Title { get; private set; }
public string Summary { get; private set; }
public IReadOnlyList<string> Content { get; private set; }
public List<string> Content { get; private set; }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Can System.Text.Json deserialize a JSON array into a constructor parameter of type List<string> while the corresponding property is declared as IReadOnlyList<string>?

💡 Result:

No, System.Text.Json cannot directly deserialize a JSON array into a constructor parameter of type List if the corresponding property is declared as IReadOnlyList [1][2][3]. The System.Text.Json serializer requires that the type of a parameter in a parameterized constructor match the type of the corresponding property or field exactly (using case-insensitive name matching) [4][5][1][2]. Even though a List is assignable to an IReadOnlyList, the serializer's constructor binding logic is restrictive and does not support this assignment automatically [2][6]. If you attempt this, the deserializer will typically throw an InvalidOperationException indicating that it cannot bind the constructor parameters [2][6][7]. To resolve this, you must align the types. The most common and recommended solutions include: 1. Update the constructor parameter to use the same interface type (i.e., use IReadOnlyList for both the property and the constructor parameter) [3][8]. System.Text.Json is capable of instantiating and populating IReadOnlyList directly [8]. 2. Use a property with a private setter and a parameterless constructor, allowing the serializer to set the property directly rather than through the constructor [1]. 3. Add an additional constructor specifically for the serializer marked with [JsonConstructor] that accepts the exact type of the property [5][1]. This strict requirement is a known behavior of System.Text.Json designed to ensure clarity and performance during the constructor binding process [2][6].

Citations:


Fix CurriculumSection.Content encapsulation and align it with System.Text.Json constructor binding

Exposing public List<string> Content allows consumers to mutate the entity after construction (Add, Clear, etc.), bypassing the constructor validation. The defensive copy in the constructor protects the input list, but the internal list reference is still exposed.

The suggested “change only the property to IReadOnlyList<string>” approach is wrong for persistence: System.Text.Json constructor binding requires the [JsonConstructor] parameter type to match the property/field type exactly—so the constructor parameter must change as well (or deserialization will fail).

♻️ Proposed fix
-    public List<string> Content { get; private set; }
+    public IReadOnlyList<string> Content { get; private set; }
@@
-    public CurriculumSection(string title, string summary, List<string> content)
+    public CurriculumSection(string title, string summary, IReadOnlyList<string> content)
     {
@@
-        Content = new List<string>(content);
+        Content = new List<string>(content).AsReadOnly();
     }

Downstream usage remains fine (e.g., GetCourseCurriculumHandler calling c.Content.ToList()).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/Src/PIED_LMS.Domain/Entities/CurriculumSection.cs` at line 9,
CurriculumSection exposes a mutable List<string> via the Content property which
breaks encapsulation and conflicts with System.Text.Json constructor binding;
change the property signature from List<string> to IReadOnlyList<string> and
update the [JsonConstructor] parameter on the CurriculumSection constructor to
also accept IReadOnlyList<string>, then store a defensive copy into a private
List<string> backing field (e.g., _content) and have the public Content return
the IReadOnlyList view (or the backing field as IReadOnlyList) so
deserialization types match and consumers cannot mutate the internal list.

@KietPham-VN KietPham-VN merged commit 6b9caec into main Jun 3, 2026
7 checks passed
@KietPham-VN KietPham-VN deleted the feat/fix-for-update-db branch June 3, 2026 03:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants