Skip to content

doc(IDynamicObject): update table dynamic data sample#7289

Merged
ArgoZhang merged 1 commit intomainfrom
doc-dynamic
Dec 10, 2025
Merged

doc(IDynamicObject): update table dynamic data sample#7289
ArgoZhang merged 1 commit intomainfrom
doc-dynamic

Conversation

@ArgoZhang
Copy link
Copy Markdown
Member

@ArgoZhang ArgoZhang commented Dec 10, 2025

Link issues

fixes #7288

Summary By Copilot

Regression?

  • Yes
  • No

Risk

  • High
  • Medium
  • Low

Verification

  • Manual (required)
  • Automated

Packaging changes reviewed?

  • Yes
  • No
  • N/A

☑️ Self Check before Merge

⚠️ Please check all items below before review. ⚠️

  • Doc is updated/provided or not needed
  • Demo is updated/provided or not needed
  • Merge the latest code from the main branch

Summary by Sourcery

Revise the dynamic table IDynamicObject sample to generate richer, strongly-typed dynamic column data and simplify column binding in the demo.

New Features:

  • Populate dynamic table sample rows with mixed-type values (text, numeric, date, boolean) for static columns to better demonstrate IDynamicObject usage.

Bug Fixes:

  • Update CustomDynamicData to store column values as object instead of string and adjust member access to support non-string dynamic types in the sample.

Enhancements:

  • Replace nullable dynamic item and column properties with initialized backing fields for more predictable component state.
  • Refactor dynamic row creation into helper methods for both static and time-based columns to centralize data generation logic.
  • Simplify table column definitions in the Razor view by binding directly to dynamic column names without per-cell templates.

Copilot AI review requested due to automatic review settings December 10, 2025 03:46
@bb-auto bb-auto Bot added the documentation Improvements or additions to documentation label Dec 10, 2025
@bb-auto bb-auto Bot added this to the v10.1.0 milestone Dec 10, 2025
@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Dec 10, 2025

Reviewer's Guide

Refactors the dynamic table IDynamicObject sample to use initialized backing fields instead of nullable properties, introduces helper methods to generate richer typed dynamic data for both static and time-based columns, simplifies Razor bindings accordingly, and generalizes CustomDynamicData to support object-valued columns with more efficient lookups.

Sequence diagram for generating static dynamic-object table rows

sequenceDiagram
    actor User
    participant Browser
    participant TablesDynamicObject
    participant CustomDynamicColumnsObjectData

    User->>Browser: Navigate_to_/table/dynamic-object
    Browser->>TablesDynamicObject: Initialize_component
    activate TablesDynamicObject
    TablesDynamicObject->>TablesDynamicObject: OnInitialized()
    TablesDynamicObject->>TablesDynamicObject: _dynamicColumnList = time_based_strings
    TablesDynamicObject->>TablesDynamicObject: _customDynamicItems = GenerateDynamicColumnsObjectData()
    loop index 1..10
        TablesDynamicObject->>TablesDynamicObject: GenerateRowData(index)
        TablesDynamicObject-->>TablesDynamicObject: rowData Dictionary~string, object?~
        TablesDynamicObject->>CustomDynamicColumnsObjectData: new(fix:index, columns:rowData)
        CustomDynamicColumnsObjectData-->>TablesDynamicObject: CustomDynamicColumnsObjectData_instance
    end
    TablesDynamicObject-->>Browser: Render_two_tables_with_dynamic_columns
    deactivate TablesDynamicObject
Loading

Sequence diagram for querying time-based dynamic columns

sequenceDiagram
    actor User
    participant Browser
    participant TableComponent as Table_CustomDynamicData
    participant TablesDynamicObject
    participant CustomDynamicData

    User->>Browser: Open_dynamic_time_based_table
    Browser->>TableComponent: Request_data
    TableComponent->>TablesDynamicObject: OnQueryAsync(options)
    activate TablesDynamicObject
    loop index 1..10
        TablesDynamicObject->>TablesDynamicObject: GenerateDynamicRowData(index)
        TablesDynamicObject-->>TablesDynamicObject: rowData Dictionary~string, object?~
        TablesDynamicObject->>CustomDynamicData: new(fix:index, data:rowData)
        CustomDynamicData-->>TablesDynamicObject: CustomDynamicData_instance
    end
    TablesDynamicObject-->>TableComponent: QueryData~CustomDynamicData~(Items, TotalCount, IsSorted, IsFiltered)
    deactivate TablesDynamicObject
    TableComponent-->>Browser: Render_rows_with_random_values_per_time_column
Loading

Updated class diagram for dynamic table sample and CustomDynamicData

classDiagram
    class TablesDynamicObject {
        -IEnumerable~CustomDynamicColumnsObjectData~ _customDynamicItems
        -List~string~ _dynamicColumnList
        +OnInitialized() void
        -GenerateDynamicColumnsObjectData() IEnumerable~CustomDynamicColumnsObjectData~
        -GenerateRowData(index int) Dictionary~string, object?~
        -GenerateDynamicRowData(index int) Dictionary~string, object?~
        -StaticColumnList List~string~$
        -random Random$
        -OnQueryAsync(options QueryPageOptions) Task~QueryData~CustomDynamicData~~
    }

    class CustomDynamicData {
        +Fix string
        +Columns Dictionary~string, object?~
        +CustomDynamicData(fix string, data Dictionary~string, object?~)
        +TryGetMember(binder GetMemberBinder, result out object?) bool
    }

    class CustomDynamicColumnsObjectData {
        +Fix string
        +Columns Dictionary~string, object?~
        +CustomDynamicColumnsObjectData(fix string, columns Dictionary~string, object?~)
    }

    class QueryData_CustomDynamicData {
        +Items IEnumerable~CustomDynamicData~
        +TotalCount int
        +IsSorted bool
        +IsFiltered bool
    }

    class QueryPageOptions {
        +PageIndex int
        +PageItems int
    }

    class DynamicObject {
    }

    TablesDynamicObject "1" --> "*" CustomDynamicColumnsObjectData
    TablesDynamicObject "1" --> "*" CustomDynamicData
    TablesDynamicObject --> QueryData_CustomDynamicData
    TablesDynamicObject --> QueryPageOptions
    CustomDynamicData --|> DynamicObject
Loading

File-Level Changes

Change Details Files
Refactor TablesDynamicObject state management and dynamic data generation logic to use backing fields and helper methods.
  • Replace nullable NotNull-annotated properties for dynamic items and dynamic column list with initialized private backing fields.
  • Generate dynamic time-based column headers into a backing list during OnInitialized.
  • Extract generation of CustomDynamicColumnsObjectData rows into a dedicated factory method that uses a helper to build per-column data dictionaries with typed values (string, int, DateTime, bool).
  • Update dynamic query handler to build CustomDynamicData rows via a helper that uses the dynamic column list and random numeric values.
src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamicObject.razor.cs
Adjust Razor component bindings to use new backing fields and simplify column templates for the demo.
  • Bind Table Items to the new _customDynamicItems backing field and iterate dynamic columns via _dynamicColumnList.
  • Simplify dynamic and static columns to plain sortable/filterable columns without custom cell templates for the sample.
  • Keep the fixed column binding unchanged while aligning naming with backing fields and static column list.
src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamicObject.razor
Generalize CustomDynamicData to support object-valued dynamic columns and improve member access performance.
  • Change Columns dictionary type from Dictionary<string, string> to Dictionary<string, object?> and update constructor signature accordingly.
  • Update TryGetMember to use TryGetValue for lookups and to return stored object values directly instead of indexing by key.
  • Maintain the special-case handling for the Fix property when accessed via dynamic binding.
src/BootstrapBlazor.Server/Data/CustomDynamicData.cs

Assessment against linked issues

Issue Objective Addressed Explanation
#7288 Update the Table dynamic data (IDynamicObject) demo/sample code to better document how to use dynamic data with the component.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@ArgoZhang ArgoZhang merged commit 4201004 into main Dec 10, 2025
5 of 6 checks passed
@ArgoZhang ArgoZhang deleted the doc-dynamic branch December 10, 2025 03:46
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • In GenerateRowData, StaticColumnList is a property that creates a new list on each access, so repeatedly calling StaticColumnList.Count and StaticColumnList[i] will allocate multiple lists and can break indexing; cache it in a local variable (e.g., var columns = StaticColumnList;) and loop over that instead.
  • GenerateDynamicRowData takes an index parameter but never uses it, so either remove the parameter or incorporate it into the generated values to avoid confusion.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `GenerateRowData`, `StaticColumnList` is a property that creates a new list on each access, so repeatedly calling `StaticColumnList.Count` and `StaticColumnList[i]` will allocate multiple lists and can break indexing; cache it in a local variable (e.g., `var columns = StaticColumnList;`) and loop over that instead.
- `GenerateDynamicRowData` takes an `index` parameter but never uses it, so either remove the parameter or incorporate it into the generated values to avoid confusion.

## Individual Comments

### Comment 1
<location> `src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamicObject.razor.cs:69` </location>
<code_context>
+        return ret;
     }

     private readonly static Random random = new();

     private Task<QueryData<CustomDynamicData>> OnQueryAsync(QueryPageOptions options)
</code_context>

<issue_to_address>
**issue (bug_risk):** Consider using a thread-safe random strategy instead of a shared static Random instance.

Because `Random` isn’t thread-safe, a shared static instance can behave incorrectly under concurrent calls to `OnQueryAsync` (e.g., contention, repeated sequences). Prefer `RandomNumberGenerator` for cryptographic needs, or `Random.Shared` / `ThreadLocal<Random>` for non-cryptographic randomness, depending on your requirements.
</issue_to_address>

### Comment 2
<location> `src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamicObject.razor.cs:79-66` </location>
<code_context>
         return Task.FromResult(new QueryData<CustomDynamicData>() { Items = items, TotalCount = 10, IsSorted = true, IsFiltered = true });
     }
+
+    private Dictionary<string, object?> GenerateDynamicRowData(int index)
+    {
+        var ret = new Dictionary<string, object?>();
+        for (int i = 0; i < _dynamicColumnList.Count; i++)
+        {
+            var columnName = _dynamicColumnList[i];
+            object? value = random.Next(1000, 9999);
+            ret.Add(columnName, value);
+        }
+        return ret;
+    }
 }
</code_context>

<issue_to_address>
**suggestion:** The index parameter of GenerateDynamicRowData is currently unused.

Since `index` isn’t used, the signature and call `GenerateDynamicRowData(index)` are misleading. Either use `index` in the generated data if it’s meant to influence the row, or remove the parameter and adjust the call site so it’s clear the row data doesn’t depend on the row index.

Suggested implementation:

```csharp
        var items = Enumerable.Range(1, 10).Select(index => new CustomDynamicData(index.ToString(), GenerateDynamicRowData()));

```

```csharp
    private Dictionary<string, object?> GenerateDynamicRowData()

```

None required beyond this file, as the only visible call site has been updated and the removed parameter was unused in the method body.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

}
ret.Add(columnName, value);
}
return ret;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: The index parameter of GenerateDynamicRowData is currently unused.

Since index isn’t used, the signature and call GenerateDynamicRowData(index) are misleading. Either use index in the generated data if it’s meant to influence the row, or remove the parameter and adjust the call site so it’s clear the row data doesn’t depend on the row index.

Suggested implementation:

        var items = Enumerable.Range(1, 10).Select(index => new CustomDynamicData(index.ToString(), GenerateDynamicRowData()));
    private Dictionary<string, object?> GenerateDynamicRowData()

None required beyond this file, as the only visible call site has been updated and the removed parameter was unused in the method body.

@codecov
Copy link
Copy Markdown

codecov Bot commented Dec 10, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (c941dc8) to head (47b09fc).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #7289   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          745       745           
  Lines        32628     32628           
  Branches      4522      4522           
=========================================
  Hits         32628     32628           
Flag Coverage Δ
BB 100.00% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the table dynamic data sample to demonstrate more flexible data types by changing from Dictionary<string, string> to Dictionary<string, object?>. This allows the sample to showcase various data types (string, int, DateTime, bool) in dynamic columns.

  • Changed CustomDynamicData.Columns type from Dictionary<string, string> to Dictionary<string, object?> to support multiple data types
  • Refactored nullable properties with [NotNull] attributes to initialized private fields following modern C# practices
  • Optimized TryGetMember to use TryGetValue pattern instead of ContainsKey followed by indexer access
  • Removed redundant template markup from razor components, simplifying the column definitions
  • Added new helper methods to generate sample data with diverse types (strings, integers, dates, booleans)

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/BootstrapBlazor.Server/Data/CustomDynamicData.cs Changed dictionary value type from string to object? and optimized member access with TryGetValue
src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamicObject.razor.cs Refactored to use private fields, added helper methods for generating diverse sample data types
src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamicObject.razor Removed redundant template markup and updated field references to match code-behind changes

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

}
else if (columnName == "Z")
{
value = i % 2 == 0;
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

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

The boolean value is calculated using the loop counter i instead of the row index. This means all rows will have the same boolean pattern based on the StaticColumnList position, not varying per row. Consider changing to value = index % 2 == 0; to make the boolean value dependent on the row number.

Suggested change
value = i % 2 == 0;
value = index % 2 == 0;

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

doc(IDynamicObject): update table dynamic data sample

2 participants