From f75aa11efe39056469ff704ef00c0117e08009b9 Mon Sep 17 00:00:00 2001 From: PavithraG-SF5066 Date: Wed, 11 Feb 2026 11:40:35 +0530 Subject: [PATCH 1/2] 1008378: added integration samples. --- .../Gantt_Dapper.Client.csproj | 17 ++ .../GanttDapper.Client/Pages/Home.razor | 49 ++++ .../GanttDapper.Client/Program.cs | 9 + .../GanttDapper.Client/_Imports.razor | 9 + .../GanttDapper/Components/App.razor | 19 ++ .../Components/Layout/MainLayout.razor | 10 + .../Components/Layout/MainLayout.razor.css | 16 ++ .../GanttDapper/Components/Pages/Error.razor | 36 +++ .../GanttDapper/Components/Routes.razor | 6 + .../GanttDapper/Components/_Imports.razor | 11 + .../Controllers/GanttController.cs | 234 ++++++++++++++++++ .../GanttDapper/GanttDapper.csproj | 20 ++ .../GanttDapper/GanttDapper.csproj.user | 9 + .../GanttDapper/Models/TaskData.cs | 88 +++++++ .../Gantt_Dapper/GanttDapper/Program.cs | 44 ++++ .../Properties/launchSettings.json | 40 +++ .../README.md | 131 ++++++++++ .../GanttMySQL/Components/App.razor | 20 ++ .../Components/Layout/MainLayout.razor | 11 + .../GanttMySQL/Components/Pages/Home.razor | 172 +++++++++++++ .../GanttMySQL/Components/Routes.razor | 6 + .../GanttMySQL/Components/_Imports.razor | 11 + .../GanttMySQL/Data/TaskDataModel.cs | 14 ++ .../GanttMySQL/Data/TaskDbContext.cs | 85 +++++++ .../GanttMySQL/Data/TaskRepository.cs | 135 ++++++++++ .../GanttMySQL/GanttMySql.csproj | 24 ++ .../GanttMySQL/GanttMySql.csproj.user | 9 + .../Blazor Web App/GanttMySQL/Program.cs | 61 +++++ .../GanttMySQL/Properties/launchSettings.json | 23 ++ .../GanttMySQL/appsettings.json | 12 + .../README.md | 166 +++++++++++++ 31 files changed, 1497 insertions(+) create mode 100644 Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/Gantt_Dapper.Client.csproj create mode 100644 Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/Pages/Home.razor create mode 100644 Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/Program.cs create mode 100644 Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/_Imports.razor create mode 100644 Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/App.razor create mode 100644 Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/Layout/MainLayout.razor create mode 100644 Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/Layout/MainLayout.razor.css create mode 100644 Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/Pages/Error.razor create mode 100644 Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/Routes.razor create mode 100644 Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/_Imports.razor create mode 100644 Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Controllers/GanttController.cs create mode 100644 Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/GanttDapper.csproj create mode 100644 Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/GanttDapper.csproj.user create mode 100644 Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Models/TaskData.cs create mode 100644 Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Program.cs create mode 100644 Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Properties/launchSettings.json create mode 100644 Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/README.md create mode 100644 Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/App.razor create mode 100644 Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/Layout/MainLayout.razor create mode 100644 Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/Pages/Home.razor create mode 100644 Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/Routes.razor create mode 100644 Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/_Imports.razor create mode 100644 Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Data/TaskDataModel.cs create mode 100644 Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Data/TaskDbContext.cs create mode 100644 Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Data/TaskRepository.cs create mode 100644 Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/GanttMySql.csproj create mode 100644 Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/GanttMySql.csproj.user create mode 100644 Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Program.cs create mode 100644 Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Properties/launchSettings.json create mode 100644 Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/appsettings.json create mode 100644 Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/README.md diff --git a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/Gantt_Dapper.Client.csproj b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/Gantt_Dapper.Client.csproj new file mode 100644 index 00000000..5d5e7bb7 --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/Gantt_Dapper.Client.csproj @@ -0,0 +1,17 @@ + + + + net9.0 + enable + enable + true + Default + + + + + + + + + diff --git a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/Pages/Home.razor b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/Pages/Home.razor new file mode 100644 index 00000000..6b7a5f3e --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/Pages/Home.razor @@ -0,0 +1,49 @@ +@page "/" +@rendermode InteractiveAuto + +@using Syncfusion.Blazor.Gantt +@using Syncfusion.Blazor.Data +@using Syncfusion.Blazor + + + + + + + + + + + + + + + + + + + + + + + +@code { + + // Keep same model names used in controller response (TaskData) + public class TaskData + { + public int? TaskId { get; set; } + public string? TaskName { get; set; } + public DateTime? StartDate { get; set; } + public DateTime? EndDate { get; set; } + public int? ParentId { get; set; } + public string Predecessor { get; set; } + public int? Duration { get; set; } + public int? Progress { get; set; } + } +} \ No newline at end of file diff --git a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/Program.cs b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/Program.cs new file mode 100644 index 00000000..b74a661a --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/Program.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; +using Syncfusion.Blazor; + + +var builder = WebAssemblyHostBuilder.CreateDefault(args); + +builder.Services.AddSyncfusionBlazor(); + +await builder.Build().RunAsync(); diff --git a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/_Imports.razor b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/_Imports.razor new file mode 100644 index 00000000..9bfbe610 --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/_Imports.razor @@ -0,0 +1,9 @@ +@using System.Net.Http +@using System.Net.Http.Json +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using static Microsoft.AspNetCore.Components.Web.RenderMode +@using Microsoft.AspNetCore.Components.Web.Virtualization +@using Microsoft.JSInterop +@using Gantt_Dapper.Client diff --git a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/App.razor b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/App.razor new file mode 100644 index 00000000..7bb30fc6 --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/App.razor @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/Layout/MainLayout.razor b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/Layout/MainLayout.razor new file mode 100644 index 00000000..c3b55acb --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/Layout/MainLayout.razor @@ -0,0 +1,10 @@ +@inherits LayoutComponentBase + +
+
+
+ @Body +
+
+
+ diff --git a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/Layout/MainLayout.razor.css b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/Layout/MainLayout.razor.css new file mode 100644 index 00000000..c3c85552 --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/Layout/MainLayout.razor.css @@ -0,0 +1,16 @@ +.page { + position: relative; + display: flex; + flex-direction: column; +} + +main { + flex: 1; +} + +@media (min-width: 641px) { + .page { + flex-direction: row; + } +} + diff --git a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/Pages/Error.razor b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/Pages/Error.razor new file mode 100644 index 00000000..b9818ce0 --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/Pages/Error.razor @@ -0,0 +1,36 @@ +@page "/Error" +@using System.Diagnostics + +Error + +

Error.

+

An error occurred while processing your request.

+ +@if (ShowRequestId) +{ +

+ Request ID: @RequestId +

+} + +

Development Mode

+

+ Swapping to Development environment will display more detailed information about the error that occurred. +

+

+ The Development environment shouldn't be enabled for deployed applications. + It can result in displaying sensitive information from exceptions to end users. + For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development + and restarting the app. +

+ +@code{ + [CascadingParameter] + private HttpContext? HttpContext { get; set; } + + private string? RequestId { get; set; } + private bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + + protected override void OnInitialized() => + RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier; +} \ No newline at end of file diff --git a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/Routes.razor b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/Routes.razor new file mode 100644 index 00000000..d39c7e89 --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/Routes.razor @@ -0,0 +1,6 @@ + + + + + + diff --git a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/_Imports.razor b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/_Imports.razor new file mode 100644 index 00000000..9ee6f787 --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Components/_Imports.razor @@ -0,0 +1,11 @@ +@using System.Net.Http +@using System.Net.Http.Json +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using static Microsoft.AspNetCore.Components.Web.RenderMode +@using Microsoft.AspNetCore.Components.Web.Virtualization +@using Microsoft.JSInterop +@using GanttDapper +@using GanttDapper.Client +@using GanttDapper.Components diff --git a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Controllers/GanttController.cs b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Controllers/GanttController.cs new file mode 100644 index 00000000..b3b7152a --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Controllers/GanttController.cs @@ -0,0 +1,234 @@ +using Microsoft.AspNetCore.Mvc; +using Syncfusion.Blazor.Data; +using Syncfusion.Blazor; +using System.ComponentModel.DataAnnotations; +using System.Data; +using Dapper; +using Microsoft.Data.SqlClient; +using System.Text.Json.Serialization; + +namespace GanttDapper.Controllers +{ + /// + /// API controller providing CRUD and query endpoints for Gantt tasks using Dapper. + /// Accepts Syncfusion DataManager requests and returns task results suitable for UrlAdaptor. + /// + [ApiController] + public class GanttController : ControllerBase + { + private readonly string ConnectionString = "Data Source=SYNCLAPN-46292\\SQLEXPRESS;Initial Catalog=ganttdb;Integrated Security=True;TrustServerCertificate=True;"; + + /// + /// Handles a DataManagerRequest from the client and returns filtered, searched, sorted and paged task data. + /// + /// The Syncfusion containing search/filter/sort/paging instructions. + /// + /// An object containing `result` (the task IEnumerable) and `count` (the total record count). + /// Returned shape matches UrlAdaptor expectations. + /// + [HttpPost] + [Route("api/[controller]")] + public object Post([FromBody] DataManagerRequest DataManagerRequest) + { + IEnumerable DataSource = GetTaskData(); + + if (DataManagerRequest.Search != null && DataManagerRequest.Search.Count > 0) + DataSource = DataOperations.PerformSearching(DataSource, DataManagerRequest.Search); + + if (DataManagerRequest.Where != null && DataManagerRequest.Where.Count > 0) + DataSource = DataOperations.PerformFiltering(DataSource, DataManagerRequest.Where, DataManagerRequest.Where[0].Operator); + + if (DataManagerRequest.Sorted != null && DataManagerRequest.Sorted.Count > 0) + DataSource = DataOperations.PerformSorting(DataSource, DataManagerRequest.Sorted); + + int TotalRecordsCount = DataSource.Count(); + + if (DataManagerRequest.Skip != 0) + DataSource = DataOperations.PerformSkip(DataSource, DataManagerRequest.Skip); + + if (DataManagerRequest.Take != 0) + DataSource = DataOperations.PerformTake(DataSource, DataManagerRequest.Take); + + return new { result = DataSource, count = TotalRecordsCount }; + } + + /// + /// Retrieves all tasks from the database ordered for hierarchical display (parents before children). + /// + /// A containing all tasks. + [Route("api/[controller]/GetTaskData")] + public List GetTaskData() + { + string Query = @"SELECT TaskId, TaskName, StartDate, EndDate, ParentId, Duration, Predecessor, Progress FROM task_data + ORDER BY CASE WHEN ParentId IS NULL THEN 0 ELSE 1 END, ParentId, TaskId;"; + + using IDbConnection Connection = new SqlConnection(ConnectionString); + Connection.Open(); + return Connection.Query(Query).ToList(); + } + + /// + /// Inserts a new task into the database and returns the created task (including assigned TaskId). + /// + /// A whose Value contains the task to insert. + /// + /// An with the created on success, or a BadRequest result with error details. + /// + [HttpPost] + [Route("api/Gantt/Insert")] + public IActionResult Insert([FromBody] CRUDModel Value) + { + try + { + var task = Value?.Value ?? new TaskData(); + + // Defaults to satisfy NOT NULL columns + task.TaskName ??= "New Task"; + task.Duration ??= 1; + task.Progress ??= 0; + task.StartDate ??= DateTime.Now; + + string Query = @"INSERT INTO task_data (TaskName, StartDate, EndDate, ParentId, Duration, Predecessor, Progress) + VALUES (@TaskName, @StartDate, @EndDate, @ParentId, @Duration, @Predecessor, @Progress); + SELECT CAST(SCOPE_IDENTITY() as int);"; + + using IDbConnection Connection = new SqlConnection(ConnectionString); + Connection.Open(); + + int newId = Connection.ExecuteScalar(Query, task); + task.TaskId = newId; + + // UrlAdaptor expects JSON response + return Ok(task); + } + catch (Exception ex) + { + // return JSON (so client won't crash JSON parsing) + return BadRequest(new { message = ex.Message, detail = ex.ToString() }); + } + } + + /// + /// Updates an existing task in the database. + /// + /// A whose Value contains the updated task data (must include TaskId). + /// + /// An with the updated on success, or a BadRequest result with error details. + /// + [HttpPost] + [Route("api/Gantt/Update")] + public IActionResult Update([FromBody] CRUDModel Value) + { + try + { + var task = Value?.Value; + + string Query = @" + UPDATE task_data + SET + TaskName = @TaskName, + StartDate = @StartDate, + EndDate = @EndDate, + ParentId = @ParentId, + Duration = @Duration, + Predecessor = @Predecessor, + Progress = @Progress + WHERE TaskId = @TaskId;"; + + using IDbConnection Connection = new SqlConnection(ConnectionString); + Connection.Open(); + Connection.Execute(Query, task); + + return Ok(task); + } + catch (Exception ex) + { + return BadRequest(new { message = ex.Message, detail = ex.ToString() }); + } + } + + /// + /// Deletes a task identified by the CRUDModel key. + /// + /// A where Key identifies the TaskId to remove. + /// + /// An with the deleted TaskId on success, or a BadRequest result with error details. + /// + [HttpPost] + [Route("api/Gantt/Delete")] + public IActionResult Delete([FromBody] CRUDModel Value) + { + try + { + int taskId = Convert.ToInt32(Value.Key?.ToString()); + + string Query = "DELETE FROM task_data WHERE TaskId = @TaskId;"; + + using IDbConnection Connection = new SqlConnection(ConnectionString); + Connection.Open(); + Connection.Execute(Query, new { TaskId = taskId }); + + return Ok(new { TaskId = taskId }); + } + catch (Exception ex) + { + return BadRequest(new { message = ex.Message, detail = ex.ToString() }); + } + } + + /// + /// Represents a task record returned to the client and stored in the `task_data` table. + /// + public class TaskData + { + [Key] + public int? TaskId { get; set; } + public string? TaskName { get; set; } + public DateTime? StartDate { get; set; } + public DateTime? EndDate { get; set; } + public int? ParentId { get; set; } + public int? Duration { get; set; } + public string Predecessor { get; set; } + public int? Progress { get; set; } + } + + /// + /// Generic CRUD wrapper used by the UrlAdaptor and server endpoints for batch and single operations. + /// + /// The payload type (e.g., ). + public class CRUDModel where T : class + { + /// The action type (for example: "insert", "update", "remove", "batch"). + [JsonPropertyName("action")] + public string? Action { get; set; } + + /// The name of the key column used by the client. + [JsonPropertyName("keyColumn")] + public string? KeyColumn { get; set; } + + /// The key value identifying a single record (for single operations). + [JsonPropertyName("key")] + public object? Key { get; set; } + + /// The single entity payload for insert/update operations. + [JsonPropertyName("value")] + public T? Value { get; set; } + + /// Collection of added records for batch operations. + [JsonPropertyName("added")] + public List? Added { get; set; } + + /// Collection of changed records for batch operations. + [JsonPropertyName("changed")] + public List? Changed { get; set; } + + /// Collection of deleted records for batch operations. + [JsonPropertyName("deleted")] + public List? Deleted { get; set; } + + /// Additional parameters sent by the client. + [JsonPropertyName("params")] + public IDictionary? Params { get; set; } + } + } +} \ No newline at end of file diff --git a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/GanttDapper.csproj b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/GanttDapper.csproj new file mode 100644 index 00000000..edace595 --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/GanttDapper.csproj @@ -0,0 +1,20 @@ + + + + net9.0 + enable + enable + + + + + + + + + + + + + + diff --git a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/GanttDapper.csproj.user b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/GanttDapper.csproj.user new file mode 100644 index 00000000..c404400a --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/GanttDapper.csproj.user @@ -0,0 +1,9 @@ + + + + https + + + ProjectDebugger + + \ No newline at end of file diff --git a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Models/TaskData.cs b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Models/TaskData.cs new file mode 100644 index 00000000..f0d32be4 --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Models/TaskData.cs @@ -0,0 +1,88 @@ +namespace Gantt_Dapper.Models +{ + public class TaskData + { + public static List task = new List(); + + public TaskData() { } + + public TaskData(int TaskId, string TaskName, DateTime? StartDate, DateTime? EndDate, int? ParentId, int Progress, string? Predecessor, string Duration) + { + this.TaskId = TaskId; + this.TaskName = TaskName; + this.StartDate = StartDate; + this.EndDate = EndDate; + this.ParentId = ParentId; + this.Progress = Progress; + this.Predecessor = Predecessor; + this.Duration = Duration; + } + public int TaskId { get; set; } + public string TaskName { get; set; } + public DateTime? StartDate { get; set; } + public DateTime? EndDate { get; set; } + public int? ParentId { get; set; } + public int Progress { get; set; } + public string? Predecessor { get; set; } + public string Duration { get; set; } + + public static List GetAllRecords() + { + List DataCollection = new List(); + + int x = 0; + int duration = 0; + + // Base start date (change if needed) + DateTime startDate = new DateTime(2026, 04, 02); + + for (int i = 1; i <= 2; i++) + { + // Create parent task (no separate variable name like parent1/parent2) + int parentId = ++x; + + DataCollection.Add(new TaskData() + { + TaskId = parentId, + TaskName = "Task " + parentId, // Parent + StartDate = startDate, + EndDate = startDate.AddDays(26), + Duration = "20", + Progress = 0, + ParentId = null, + Predecessor = null + }); + + // Reset child start for each parent + DateTime childStart = startDate; + + for (int j = 1; j <= 4; j++) + { + // Move start like your sample: first child same date, next children based on duration+2 + childStart = childStart.AddDays(j == 1 ? 0 : duration + 2); + duration = 5; + + int childId = ++x; + + DataCollection.Add(new TaskData() + { + TaskId = childId, + TaskName = "Task " + childId, // Child + StartDate = childStart, + EndDate = childStart.AddDays(duration), + Duration = duration.ToString(), + Progress = 0, + ParentId = parentId, + Predecessor = j > 1 ? (childId - 1) + "FS" : null + }); + } + + // Move next parent start date after current parent ends (+2 days gap) + startDate = startDate.AddDays(28); + duration = 0; + } + + return DataCollection; + } + } +} diff --git a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Program.cs b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Program.cs new file mode 100644 index 00000000..253d46ac --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Program.cs @@ -0,0 +1,44 @@ +using GanttDapper.Client.Pages; +using GanttDapper.Components; +using Syncfusion.Blazor; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +builder.Services.AddRazorComponents() + .AddInteractiveServerComponents() + .AddInteractiveWebAssemblyComponents(); + +builder.Services.AddSyncfusionBlazor(); +builder.Services.AddControllers(); + +builder.Services.AddServerSideBlazor() + .AddCircuitOptions(options => { options.DetailedErrors = true; }); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseWebAssemblyDebugging(); +} +else +{ + app.UseExceptionHandler("/Error", createScopeForErrors: true); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); +} + +app.UseHttpsRedirection(); + + +app.UseAntiforgery(); +app.MapControllers(); + +app.MapStaticAssets(); +app.MapRazorComponents() + .AddInteractiveServerRenderMode() + .AddInteractiveWebAssemblyRenderMode() + .AddAdditionalAssemblies(typeof(GanttDapper.Client._Imports).Assembly); + +app.Run(); diff --git a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Properties/launchSettings.json b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Properties/launchSettings.json new file mode 100644 index 00000000..9510b85b --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Properties/launchSettings.json @@ -0,0 +1,40 @@ +{ + "profiles": { + "http": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "applicationUrl": "http://localhost:5298" + }, + "https": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "applicationUrl": "https://localhost:7237;http://localhost:5298" + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + }, + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:52188/", + "sslPort": 44309 + } + } +} \ No newline at end of file diff --git a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/README.md b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/README.md new file mode 100644 index 00000000..674bd28e --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/README.md @@ -0,0 +1,131 @@ +# Blazor Gantt with MS SQL and Dapper + +## Project Overview + +This repository demonstrates a straightforward pattern for binding **MS SQL Server** database to **Syncfusion Blazor Gantt** using **[Dapper](https://www.nuget.org/packages/Dapper)** and the UrlAdaptor from SfDataManager. The sample provides full CRUD (Create, Read, Update, Delete) functionality, filtering, sorting, and hierarchical parent/child support. + +## Key Features + +- **MS SQL**: Reliable relational database for production environments and LocalDB support for development. +- **Dapper**: Lightweight, high-performance micro‑ORM for parameterized SQL and fast data mapping. +- **Syncfusion Blazor Gantt**: Built-in editing, inserting, deleting, filtering, sorting, and parent/child hierarchy (via ParentId). +- **UrlAdaptor**: API communication for all CRUD actions. + +## Prerequisites + +| Component | Version | Purpose | +|-----------|---------|---------| +| Visual Studio 2026 | 18.1.0 or later | Development IDE with Blazor workload | +| .NET SDK | net10.0 or compatible | Runtime and build tools | +| [SQL Server Management Studio]| Latest | Core framework for database operations | +| [Dapper] | 2.1.66 or latest | Lightweight data mapper | +| [Microsoft.Data.SqlClient] | 6.1.4 or Latest | SQL Server client driver | +| [Syncfusion.Blazor.Gantt] | 32.1.25 or Latest | Gantt and UI components | +| [Syncfusion.Blazor.Themes] | 32.1.25 or Latest | Styling for Gantt components | + +## Quick Start + +1. **Clone the repository** + ```bash + git clone + cd "Binding Dapper using UrlAdaptor" + cd "Blazor Web app/GanttDapper" + ``` + +2. **Create the database and table** + + Open MS SQL and run: + ```sql + CREATE DATABASE ganttdb; + USE ganttdb; + + CREATE TABLE task_data ( + TaskId INT PRIMARY KEY, + TaskName VARCHAR(50) NOT NULL, + StartDate DATETIME NULL, + EndDate DATETIME NULL, + ParentId INT NULL, + Duration INT NOT NULL, + Predecessor VARCHAR(50) NULL, + Progress INT NOT NULL + ); + ``` + +3. **Update the connection string** + + Replace connected database's connectionstring in GanttController.cs file in Controllers folder of Gantt_Dapper. + +4. **Restore packages and build** + ```bash + dotnet restore + dotnet build + ``` + +5. **Run the application** + ```bash + dotnet run + ``` + +6. **Open the application** + + Navigate to the local URL displayed in the terminal (typically `https://localhost:xxxx`). + + +## Project Layout + +| File/Folder | Purpose | +|-------------|---------| +| `Controllers/GanttController.cs` | API controller with Dapper queries for CRUD | +| `/Components/Pages/Home.razor` | Gantt page with UrlAdaptor implementation | +| `/Program.cs` | Service registration and Syncfusion configuration | + + +## Common Tasks + +### Add a Task +1. Click the **Add** button in the toolbar +2. Fill in the Dialog fields +3. Click **Save** to persist the record to the database + +### Edit a Task +1. Select a task row in the gantt +2. Click the **Edit** button in the toolbar +3. Modify the required fields +4. Click **Save** to save changes + +### Delete a Task +1. Select a task row in the gantt +2. Click the **Delete** button in the toolbar +3. Confirm the deletion in the dialog + +### Search Records +1. Use the **Search** box in the toolbar +2. Enter keywords to filter records (searches across all columns) + +### Filter Records +1. Click the filter icon in any column header +2. Select filter criteria (equals, contains, greater than, etc.) +3. Click **Filter** to apply + +### Sort Records +1. Click the column header to sort ascending +2. Click again to sort descending + +## Troubleshooting + +### Connection Error +- Verify SQL Server is running and reachable. +- Test connection in SSMS with same credentials. + +### Missing Tables +- Verify the SQL script was executed successfully +- Run the database creation script again + +### Static Files Not Loading +- Verify Syncfusion stylesheet and script references are present in `App.razor` +- Check browser developer tools for 404 errors on static resources + +### Version Conflicts +- Align Entity Framework Core, Pomelo, and Syncfusion package versions +- Run `dotnet restore` to update NuGet packages +- Check the `.csproj` file for conflicting version constraints diff --git a/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/App.razor b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/App.razor new file mode 100644 index 00000000..ae4ca78b --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/App.razor @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/Layout/MainLayout.razor b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/Layout/MainLayout.razor new file mode 100644 index 00000000..f8c3a56c --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/Layout/MainLayout.razor @@ -0,0 +1,11 @@ +@inherits LayoutComponentBase + +
+
+
+ @Body +
+
+
+ + diff --git a/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/Pages/Home.razor b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/Pages/Home.razor new file mode 100644 index 00000000..cd5727ea --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/Pages/Home.razor @@ -0,0 +1,172 @@ +@page "/" +@rendermode InteractiveServer + +@using System.Collections +@using Syncfusion.Blazor.Data +@using Syncfusion.Blazor.Gantt +@using GanttMySql.Data + +@inject TaskRepository TaskService + + + + + + + + + + + + + + + + + + + + + +@code { + private CustomAdaptor? _customAdaptor; + + /// + /// Initializes the component and sets up the custom adaptor with the injected TaskService. + /// + protected override void OnInitialized() + { + _customAdaptor = new CustomAdaptor { TaskService = TaskService }; + } + + /// + /// Custom DataAdaptor to handle Gantt data operations with MySQL using EF Core. + /// Bridges Syncfusion DataManager requests to the repository. + /// + public class CustomAdaptor : DataAdaptor + { + private static TaskRepository? _taskService { get; set; } + + /// + /// Task repository instance used to fulfill data operations. + /// + public TaskRepository? TaskService + { + get => _taskService; + set => _taskService = value; + } + + /// + /// Reads data according to DataManagerRequest (search, sort, paging). + /// + /// The DataManagerRequest containing query, paging, sorting, and search criteria. + /// Optional key value for single-record reads. + /// + /// Returns either a (when counts are requested) or the IEnumerable of tasks as an object. + /// + public override async Task ReadAsync(DataManagerRequest dm, string? key = null) + { + IEnumerable dataSource = await _taskService!.GetTasksAsync(); + + // Search + if (dm.Search != null && dm.Search.Count > 0) + dataSource = DataOperations.PerformSearching(dataSource, dm.Search); + + // Sort + if (dm.Sorted != null && dm.Sorted.Count > 0) + dataSource = DataOperations.PerformSorting(dataSource, dm.Sorted); + + int count = dataSource.Cast().Count(); + + // Paging + if (dm.Skip != 0) dataSource = DataOperations.PerformSkip(dataSource, dm.Skip); + if (dm.Take != 0) dataSource = DataOperations.PerformTake(dataSource, dm.Take); + + return dm.RequiresCounts + ? new DataResult() { Result = dataSource, Count = count } + : (object)dataSource; + } + + /// + /// Updates a task record using the repository. + /// + /// The DataManager instance (framework-provided). + /// The updated object (expected ). + /// Optional key field name. + /// Key value identifying the record. + /// The updated object. + public override async Task UpdateAsync(DataManager dm, object value, string? keyField, string key) + { + await _taskService!.UpdateTaskAsync(value as TaskDataModel); + return value; + } + + /// + /// Removes a task record using the repository. + /// + /// The DataManager instance (framework-provided). + /// The object representing the record to remove (various types supported). + /// Optional key field name. + /// Key value identifying the record. + /// The removed object. + public override async Task RemoveAsync(DataManager dm, object value, string? keyField, string key) + { + int? taskId = value switch + { + int i => i, + long l => (int)l, + string s when int.TryParse(s, out var id) => id, + TaskDataModel t => t.TaskId, + _ => null + }; + + await _taskService!.RemoveTaskAsync(taskId); + return value; + } + + /// + /// Applies batch changes: updates, inserts, and deletes using the repository. + /// + /// The DataManager instance (framework-provided). + /// Records that were modified. + /// Records that were added. + /// Records that were deleted. + /// Optional key field name. + /// Key value used by the batch operation. + /// Optional drop index for drag-and-drop operations. + /// A task that yields the batch operation key or result. + public override async Task BatchUpdateAsync(DataManager dm, object changedRecords, object addedRecords, object deletedRecords, string? keyField, string key, int? dropIndex) + { + if (changedRecords is IEnumerable changed) + { + foreach (var record in changed) + { + // Debug (optional) + Console.WriteLine($"UPDATE TaskId={record.TaskId}, ParentId={record.ParentId}"); + await _taskService!.UpdateTaskAsync(record); + } + } + + if (addedRecords is IEnumerable added) + { + foreach (var record in added) + { + // Debug (optional) + Console.WriteLine($"INSERT TaskId={record.TaskId}, ParentId={record.ParentId}"); + + record.TaskId = 0; // identity insert + await _taskService!.AddTaskAsync(record); + } + } + + if (deletedRecords is IEnumerable deleted) + { + foreach (var record in deleted) + await _taskService!.RemoveTaskAsync(record.TaskId); + } + + return key; + } + } +} diff --git a/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/Routes.razor b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/Routes.razor new file mode 100644 index 00000000..f756e19d --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/Routes.razor @@ -0,0 +1,6 @@ + + + + + + diff --git a/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/_Imports.razor b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/_Imports.razor new file mode 100644 index 00000000..97e6747b --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/_Imports.razor @@ -0,0 +1,11 @@ +@using System.Net.Http +@using System.Net.Http.Json +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using static Microsoft.AspNetCore.Components.Web.RenderMode +@using Microsoft.AspNetCore.Components.Web.Virtualization +@using Microsoft.JSInterop +@using GanttMySql +@using GanttMySql.Components +@using Syncfusion.Blazor diff --git a/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Data/TaskDataModel.cs b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Data/TaskDataModel.cs new file mode 100644 index 00000000..155d0b4e --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Data/TaskDataModel.cs @@ -0,0 +1,14 @@ +namespace GanttMySql.Data +{ + public class TaskDataModel + { + public int TaskId { get; set; } + public string? TaskName { get; set; } + public DateTime? StartDate { get; set; } + public DateTime? EndDate { get; set; } + public int? ParentId { get; set; } + public string Predecessor { get; set; } + public string? Duration { get; set; } + public int Progress { get; set; } + } +} diff --git a/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Data/TaskDbContext.cs b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Data/TaskDbContext.cs new file mode 100644 index 00000000..b870b465 --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Data/TaskDbContext.cs @@ -0,0 +1,85 @@ +using Microsoft.EntityFrameworkCore; + +namespace GanttMySql.Data +{ + /// + /// DbContext for task_data table. + /// Manages DB connection and entity configuration for TaskDataModel. + /// + public class TaskDbContext : DbContext + { + /// + /// Initializes a new instance of . + /// + /// The options for this context. + public TaskDbContext(DbContextOptions options) + : base(options) + { + } + + /// + /// Gets the representing the task_data table. + /// + public DbSet TaskData => Set(); + + /// + /// Configures entity mappings and constraints. + /// + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity(entity => + { + // Table name + entity.ToTable("task_data"); + + // Primary Key + entity.HasKey(e => e.TaskId); + + // Auto-increment for Primary Key + entity.Property(e => e.TaskId) + .ValueGeneratedOnAdd(); + + // TaskName (NOT NULL, VARCHAR(50)) + entity.Property(e => e.TaskName) + .HasMaxLength(50) + .IsRequired(); + + // StartDate (DATETIME, nullable) + entity.Property(e => e.StartDate) + .HasColumnType("datetime") + .IsRequired(false); + + // EndDate (DATETIME, nullable) + entity.Property(e => e.EndDate) + .HasColumnType("datetime") + .IsRequired(false); + + // ParentId (INT, nullable) + entity.Property(e => e.ParentId) + .IsRequired(false); + + // Predecessor (VARCHAR(100), nullable) + entity.Property(e => e.Predecessor) + .HasMaxLength(100) + .IsRequired(false); + + // Duration (NOT NULL, VARCHAR(10)) + entity.Property(e => e.Duration) + .HasMaxLength(10) + .IsRequired(); + + // Progress (NOT NULL, INT) + entity.Property(e => e.Progress) + .HasColumnType("int") + .IsRequired(); + + // Helpful indexes + entity.HasIndex(e => e.ParentId).HasDatabaseName("IX_Task_ParentId"); + entity.HasIndex(e => e.StartDate).HasDatabaseName("IX_Task_StartDate"); + }); + } + } +} + diff --git a/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Data/TaskRepository.cs b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Data/TaskRepository.cs new file mode 100644 index 00000000..d9a34d67 --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Data/TaskRepository.cs @@ -0,0 +1,135 @@ +using GanttMySql.Data; +using Microsoft.EntityFrameworkCore; + +namespace GanttMySql.Data +{ + /// + /// Repository implementation for TaskDataModel using EF Core. + /// Handles CRUD operations and simple task business rules. + /// + public class TaskRepository + { + private readonly TaskDbContext _context; + + /// + /// Initializes a new instance of . + /// + /// The used to access the database. + public TaskRepository(TaskDbContext context) + { + _context = context; + } + + /// + /// Retrieves all tasks ordered for hierarchical display. + /// + /// A list of instances. + public async Task> GetTasksAsync() + { + try + { + return await _context.TaskData + .OrderBy(t => t.ParentId == null ? 0 : 1) + .ThenBy(t => t.ParentId) + .ThenBy(t => t.TaskId) + .ToListAsync(); + } + catch (Exception ex) + { + Console.WriteLine($"Error retrieving tasks: {ex.Message}"); + throw; + } + } + + /// + /// Adds a new task to the database with defaults and validation. + /// + /// The task to add. + public async Task AddTaskAsync(TaskDataModel task) + { + if (task == null) + throw new ArgumentNullException(nameof(task), "Task cannot be null"); + + // Ensure DB generates identity + task.TaskId = 0; + + ApplyDefaults(task); + + _context.TaskData.Add(task); + await _context.SaveChangesAsync(); + } + + /// + /// Updates an existing task in the database. + /// + /// Updated task data (TaskId must identify an existing task). + public async Task UpdateTaskAsync(TaskDataModel task) + { + if (task == null) + throw new ArgumentNullException(nameof(task), "Task cannot be null"); + + var existing = await _context.TaskData.FindAsync(task.TaskId); + if (existing == null) + throw new KeyNotFoundException($"Task with ID {task.TaskId} not found in the database."); + + ApplyDefaults(task); + + existing.TaskName = task.TaskName; + existing.StartDate = task.StartDate; + existing.EndDate = task.EndDate; + existing.Duration = task.Duration; + existing.Progress = task.Progress; + existing.Predecessor = task.Predecessor; + existing.ParentId = task.ParentId; + + await _context.SaveChangesAsync(); + } + + /// + /// Deletes a task by TaskId. + /// + /// Task identifier to remove; null or invalid values are ignored. + public async Task RemoveTaskAsync(int? key) + { + if (key == null || key <= 0) + return; // don’t throw for invalid key in UI flows + + try + { + var task = await _context.TaskData.FindAsync(key.Value); + + if (task == null) + return; + + _context.TaskData.Remove(task); + await _context.SaveChangesAsync(); + } + catch (DbUpdateException ex) + { + Console.WriteLine($"Database error while deleting task: {ex.Message}"); + throw; + } + } + + /// + /// Applies default values and enforces simple business rules on a task instance. + /// + /// Task instance to modify in-place. + private static void ApplyDefaults(TaskDataModel task) + { + task.TaskName = string.IsNullOrWhiteSpace(task.TaskName) ? "New Task" : task.TaskName.Trim(); + task.StartDate ??= DateTime.Now; + + if (string.IsNullOrWhiteSpace(task.Duration)) + task.Duration = "1 day"; // or "1d" + + // Clamp progress 0..100 + if (task.Progress < 0) task.Progress = 0; + if (task.Progress > 100) task.Progress = 100; + + if (task.EndDate != null && task.StartDate != null && task.EndDate < task.StartDate) + task.EndDate = task.StartDate.Value.AddDays(1); + } + } +} + diff --git a/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/GanttMySql.csproj b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/GanttMySql.csproj new file mode 100644 index 00000000..a4d8d7b5 --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/GanttMySql.csproj @@ -0,0 +1,24 @@ + + + + net10.0 + enable + enable + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + diff --git a/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/GanttMySql.csproj.user b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/GanttMySql.csproj.user new file mode 100644 index 00000000..983ecfc0 --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/GanttMySql.csproj.user @@ -0,0 +1,9 @@ + + + + http + + + ProjectDebugger + + \ No newline at end of file diff --git a/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Program.cs b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Program.cs new file mode 100644 index 00000000..599216ff --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Program.cs @@ -0,0 +1,61 @@ +using GanttMySql.Components; +using GanttMySql.Data; +using Syncfusion.Blazor; +using Microsoft.EntityFrameworkCore; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +builder.Services.AddRazorComponents() + .AddInteractiveServerComponents(); +builder.Services.AddSyncfusionBlazor(); + +// ========== ENTITY FRAMEWORK CORE CONFIGURATION ========== +// Get connection string from appsettings.json +var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); + +if (string.IsNullOrEmpty(connectionString)) +{ + throw new InvalidOperationException("Connection string 'DefaultConnection' not found in configuration."); +} + + +builder.Services.AddDbContext(options => +{ + options.UseMySql( + connectionString, + ServerVersion.AutoDetect(connectionString) + ); + + // Enable detailed error messages in development + if (builder.Environment.IsDevelopment()) + { + options.EnableSensitiveDataLogging(); + } +}); + +// Register Repository for dependency injection +builder.Services.AddScoped(); + +// ======================================================== + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (!app.Environment.IsDevelopment()) +{ + app.UseExceptionHandler("/Error", createScopeForErrors: true); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); +} + +app.UseHttpsRedirection(); + + +app.UseAntiforgery(); + +app.MapStaticAssets(); +app.MapRazorComponents() + .AddInteractiveServerRenderMode(); + +app.Run(); diff --git a/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Properties/launchSettings.json b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Properties/launchSettings.json new file mode 100644 index 00000000..28f27e35 --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Properties/launchSettings.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:5250", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:7222;http://localhost:5250", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } + } diff --git a/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/appsettings.json b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/appsettings.json new file mode 100644 index 00000000..1a8afc65 --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/appsettings.json @@ -0,0 +1,12 @@ +{ + "ConnectionStrings": { + "DefaultConnection": "Server=localhost;Port=3306;Database=ganttdb;Uid=root;Pwd=Mysql@890;SslMode=None;ConvertZeroDateTime=false;" + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/README.md b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/README.md new file mode 100644 index 00000000..ec6b9fdf --- /dev/null +++ b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/README.md @@ -0,0 +1,166 @@ +# Blazor Gantt Chart with MySQL and Entity Framework Core + +## Project Overview + +This repository demonstrates a production-ready pattern for binding **MySQL Server** data to **Syncfusion Blazor Gantt** using **Entity Framework Core (EF Core)**. The sample application provides complete CRUD (Create, Read, Update, Delete) operations, filtering, sorting, and batch updates. The implementation follows industry best practices using models, DbContext, repository pattern, and a custom adaptor for seamless functionality. + +## Key Features + +- **MySQL–Entity Framework Core Integration**: Models, DbContext, and Entity Framework Core migrations for database operations +- **Syncfusion Blazor Gantt**: Built-in search, filter, sorting capabilities +- **Complete CRUD Operations**: Add, edit, delete, and batch update records directly from the Gantt +- **Repository Pattern**: Clean separation of concerns with dependency injection support +- **CustomAdaptor**: Full control over data operations (read, search, filter, sort) +- **Configurable Connection String**: Database credentials managed via `appsettings.json` + +## Prerequisites + +| Component | Version | Purpose | +|-----------|---------|---------| +| Visual Studio 2026 | 18.1.0 or later | Development IDE with Blazor workload | +| .NET SDK | net10.0 or compatible | Runtime and build tools | +| MySQL Server | 8.0.45 or later | Database server | +| Microsoft.EntityFrameworkCore | 10.0.0 or later | Core framework for database operations | +| Microsoft.EntityFrameworkCore.Tools | 10.0.0 or later | Tools for managing database migrations | +| Pomelo.EntityFrameworkCore.MySql | 10.0.0 or later | MySQL provider for Entity Framework Core | +| Syncfusion.Blazor.Gantt | Latest | Gantt and UI components | +| Syncfusion.Blazor.Themes | Latest | Styling for Gantt components | + +## Quick Start + +1. **Clone the repository** + ```bash + git clone + cd "Binding MySQL database using CustomAdaptor" + cd "Blazor Web app/GanttMySql" + ``` + +2. **Create the database and table** + + Open MySQL Workbench or any MySQL client and run: + ```sql + CREATE DATABASE IF NOT EXISTS ganttdb; + USE ganttdb; + + CREATE TABLE IF NOT EXISTS task_data ( + TaskId INT AUTO_INCREMENT PRIMARY KEY, + TaskName VARCHAR(50) NOT NULL, + StartDate DATETIME, + EndDate DATETIME, + ParentId INT NULL, + Predecessor VARCHAR(50) NULL, + Duration VARCHAR(10) NOT NULL, + Progress INT NOT NULL + ); + ``` + +3. **Update the connection string** + + Open `appsettings.json` and configure the MySQL connection: + ```json + { + "ConnectionStrings": { + "DefaultConnection": "Server=localhost;Port=3306;Database=ganttdb;Uid=root;Pwd=;SslMode=None;ConvertZeroDateTime=true;" + }, + "AllowedHosts": "*" + } + ``` + Replace `ganttdb` with your actual database name in the connection string. + +4. **Restore packages and build** + ```bash + dotnet restore + dotnet build + ``` + +5. **Run the application** + ```bash + dotnet run + ``` + +6. **Open the application** + + Navigate to the local URL displayed in the terminal (typically `https://localhost:xxxx`). + +## Configuration + +### Connection String + +The connection string in `appsettings.json` contains the following components: + +| Component | Description | Example | +|-----------|-------------|---------| +| Server | MySQL server address | `localhost` | +| Port | MySQL port number | `3306` | +| Database | Database name | `ganttdb` | +| Uid | MySQL username | `root` | +| Pwd | MySQL password | `` | +| SslMode | SSL encryption mode | `None` (for local development) | + +**Security Note**: For production environments, store sensitive credentials using: +- User secrets for development +- Environment variables for production +- Azure Key Vault or similar secure storage solutions + +## Project Layout + +| File/Folder | Purpose | +|-------------|---------| +| `/Data/TaskDataModel.cs` | Entity model representing the transactions table | +| `/Data/TaskDbContext.cs` | Entity Framework Core DbContext for database operations | +| `/Data/TaskRepository.cs` | Repository class providing CRUD methods | +| `/Components/Pages/Home.razor` | Gantt Chart Sample with CustomAdaptor implementation | +| `/Program.cs` | Service registration and Syncfusion configuration | +| `/appsettings.json` | Application configuration including connection string | + +## Common Tasks + +### Add a Task +1. Click the **Add** button in the toolbar +2. Fill in the Dialog fields +3. Click **Save** to persist the record to the database + +### Edit a Task +1. Select a task row in the Gantt +2. Click the **Edit** button in the toolbar +3. Modify the required fields in the edit dialog +4. Click **Save** to save changes + +### Delete a Task +1. Select a task row in the Gantt +2. Click the **Delete** button in the toolbar +3. Confirm the deletion in the dialog + +### Search Records +1. Use the **Search** box in the toolbar +2. Enter keywords to filter records (searches across all columns) + +### Filter Records +1. Click the filter icon in any column header +2. Select filter criteria (equals, contains, greater than, etc.) +3. Click **Filter** to apply + +### Sort Records +1. Click the column header to sort ascending +2. Click again to sort descending + +## Troubleshooting + +### Connection Error +- Verify MySQL Server is running on the specified host and port +- Confirm the database name, username, and password are correct +- Ensure the `ganttdb` database exists + +### Missing Tables +- Verify the SQL script was executed successfully +- Check that migrations were applied (if using EF migrations) +- Run the database creation script again + +### Static Files Not Loading +- Verify Syncfusion stylesheet and script references are present in `App.razor` +- Check browser developer tools for 404 errors on static resources + +### Version Conflicts +- Align Entity Framework Core, Pomelo, and Syncfusion package versions +- Run `dotnet restore` to update NuGet packages +- Check the `.csproj` file for conflicting version constraints From 5a4453717088b693a5e4548a62a16705738bfcc7 Mon Sep 17 00:00:00 2001 From: PavithraG-SF5066 Date: Thu, 12 Feb 2026 16:37:03 +0530 Subject: [PATCH 2/2] 1008378: added code changes. --- ...lient.csproj => GanttDapper.Client.csproj} | 0 .../GanttDapper.Client/Pages/Home.razor | 2 +- .../GanttDapper.Client/_Imports.razor | 2 +- .../GanttDapper/GanttDapper.csproj | 2 +- .../GanttDapper/Models/TaskData.cs | 88 ------------------- .../GanttMySQL/Components/Pages/Home.razor | 12 ++- 6 files changed, 14 insertions(+), 92 deletions(-) rename Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/{Gantt_Dapper.Client.csproj => GanttDapper.Client.csproj} (100%) delete mode 100644 Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Models/TaskData.cs diff --git a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/Gantt_Dapper.Client.csproj b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/GanttDapper.Client.csproj similarity index 100% rename from Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/Gantt_Dapper.Client.csproj rename to Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/GanttDapper.Client.csproj diff --git a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/Pages/Home.razor b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/Pages/Home.razor index 6b7a5f3e..ed2a6756 100644 --- a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/Pages/Home.razor +++ b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper.Client/Pages/Home.razor @@ -5,7 +5,7 @@ @using Syncfusion.Blazor.Data @using Syncfusion.Blazor - - + diff --git a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Models/TaskData.cs b/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Models/TaskData.cs deleted file mode 100644 index f0d32be4..00000000 --- a/Gantt/IntegrationWithNet10/Binding Dapper using Url Adaptor/Blazor Web App/Gantt_Dapper/GanttDapper/Models/TaskData.cs +++ /dev/null @@ -1,88 +0,0 @@ -namespace Gantt_Dapper.Models -{ - public class TaskData - { - public static List task = new List(); - - public TaskData() { } - - public TaskData(int TaskId, string TaskName, DateTime? StartDate, DateTime? EndDate, int? ParentId, int Progress, string? Predecessor, string Duration) - { - this.TaskId = TaskId; - this.TaskName = TaskName; - this.StartDate = StartDate; - this.EndDate = EndDate; - this.ParentId = ParentId; - this.Progress = Progress; - this.Predecessor = Predecessor; - this.Duration = Duration; - } - public int TaskId { get; set; } - public string TaskName { get; set; } - public DateTime? StartDate { get; set; } - public DateTime? EndDate { get; set; } - public int? ParentId { get; set; } - public int Progress { get; set; } - public string? Predecessor { get; set; } - public string Duration { get; set; } - - public static List GetAllRecords() - { - List DataCollection = new List(); - - int x = 0; - int duration = 0; - - // Base start date (change if needed) - DateTime startDate = new DateTime(2026, 04, 02); - - for (int i = 1; i <= 2; i++) - { - // Create parent task (no separate variable name like parent1/parent2) - int parentId = ++x; - - DataCollection.Add(new TaskData() - { - TaskId = parentId, - TaskName = "Task " + parentId, // Parent - StartDate = startDate, - EndDate = startDate.AddDays(26), - Duration = "20", - Progress = 0, - ParentId = null, - Predecessor = null - }); - - // Reset child start for each parent - DateTime childStart = startDate; - - for (int j = 1; j <= 4; j++) - { - // Move start like your sample: first child same date, next children based on duration+2 - childStart = childStart.AddDays(j == 1 ? 0 : duration + 2); - duration = 5; - - int childId = ++x; - - DataCollection.Add(new TaskData() - { - TaskId = childId, - TaskName = "Task " + childId, // Child - StartDate = childStart, - EndDate = childStart.AddDays(duration), - Duration = duration.ToString(), - Progress = 0, - ParentId = parentId, - Predecessor = j > 1 ? (childId - 1) + "FS" : null - }); - } - - // Move next parent start date after current parent ends (+2 days gap) - startDate = startDate.AddDays(28); - duration = 0; - } - - return DataCollection; - } - } -} diff --git a/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/Pages/Home.razor b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/Pages/Home.razor index cd5727ea..53c4454a 100644 --- a/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/Pages/Home.razor +++ b/Gantt/IntegrationWithNet10/Binding Mysql DB using Custom Adaptor/Blazor Web App/GanttMySQL/Components/Pages/Home.razor @@ -8,7 +8,7 @@ @inject TaskRepository TaskService - @@ -73,6 +73,16 @@ if (dm.Search != null && dm.Search.Count > 0) dataSource = DataOperations.PerformSearching(dataSource, dm.Search); + if (dm.Where != null && dm.Where.Count > 0) + { + // Filtering + if (dm.Where[0].Field != null && dm.Where[0].Field == nameof(TaskDataModel.ParentId)) { } + else + { + dataSource = DataOperations.PerformFiltering(dataSource, dm.Where, dm.Where[0].Operator); + } + } + // Sort if (dm.Sorted != null && dm.Sorted.Count > 0) dataSource = DataOperations.PerformSorting(dataSource, dm.Sorted);