CHAPTER 6

Figure 57: Database Diagram
We will now add tables to the database to support the custom code we plan to write. To allow our code to communicate with these tables, we require a data layer. This data layer will also allow us to organize and reuse code efficiently.
The diagram in Figure 57 shows the relationship between the tables. A SyncfusionHelpDeskTickets record is created first. As the issue is processed, multiple associated SyncfusionHelpDeskTicketDetails records are added.
The SyncfusionHelpDeskTickets table also has a relationship to the Oqtane framework Module table.
Oqtane has a technique to upgrade modules that allows us to create additional SQL scripts to add new database tables.
The first step is to add the database tables we will need. To do this, we will add the SQL scripts required to create the database tables. Oqtane will execute the scripts when the module is reinstalled.

Figure 58: Syncfusion.Helpdesk.1.0.1.sql
Add a new file, Syncfusion.Helpdesk.1.0.1.sql, to the Server project (in the Scripts folder) using the following code.
Code Listing 12: Syncfusion.Helpdesk.1.0.0.sql
/* Create SyncfusionHelpDesk tables. */ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[SyncfusionHelpDeskTicketDetails]( [HelpDeskTicketDetailId] [int] IDENTITY(1,1) NOT NULL, [HelpDeskTicketId] [int] NOT NULL, [TicketDetailDate] [datetime] NOT NULL, [TicketDescription] [nvarchar](max) NOT NULL, [CreatedBy] [nvarchar](256) NOT NULL, [CreatedOn] [datetime] NOT NULL, [ModifiedBy] [nvarchar](256) NOT NULL, [ModifiedOn] [datetime] NOT NULL, CONSTRAINT [PK_SyncfusionHelpDeskTicketDetails] PRIMARY KEY CLUSTERED ( [HelpDeskTicketDetailId] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[SyncfusionHelpDeskTickets]( [HelpDeskTicketId] [int] IDENTITY(1,1) NOT NULL, [ModuleId] [int] NOT NULL, [TicketStatus] [nvarchar](50) NOT NULL, [TicketDate] [datetime] NOT NULL, [TicketDescription] [nvarchar](max) NOT NULL, [CreatedBy] [nvarchar](256) NOT NULL, [CreatedOn] [datetime] NOT NULL, [ModifiedBy] [nvarchar](256) NOT NULL, [ModifiedOn] [datetime] NOT NULL, CONSTRAINT [PK_HelpDeskTickets] PRIMARY KEY CLUSTERED ( [HelpDeskTicketId] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO ALTER TABLE [dbo].[SyncfusionHelpDeskTicketDetails] WITH CHECK ADD CONSTRAINT [FK_SyncfusionHelpDeskTicketDetails_SyncfusionHelpDeskTickets] FOREIGN KEY([HelpDeskTicketId]) REFERENCES [dbo].[SyncfusionHelpDeskTickets] ([HelpDeskTicketId]) ON DELETE CASCADE GO ALTER TABLE [dbo].[SyncfusionHelpDeskTicketDetails] CHECK CONSTRAINT [FK_SyncfusionHelpDeskTicketDetails_SyncfusionHelpDeskTickets] GO /* Create foreign key relationships. */ ALTER TABLE [dbo].[SyncfusionHelpDeskTickets] WITH CHECK ADD CONSTRAINT [FK_SyncfusionHelpDeskTickets_Module] FOREIGN KEY([ModuleId]) REFERENCES [dbo].[Module] ([ModuleId]) ON DELETE CASCADE GO ALTER TABLE [dbo].[SyncfusionHelpDeskTickets] CHECK CONSTRAINT [FK_SyncfusionHelpDeskTickets_Module] GO |

Figure 59: Set to Embedded resource
Click the file in the Solution Explorer, and in the Properties, set the Build Action to Embedded resource.
So that the database tables will be removed when the module is uninstalled, open the Syncfusion.Helpdesk.Uninstall.sql file and replace all the code with the following code.
Code Listing 13: Syncfusion.Helpdesk.Uninstall.sql
/* Remove SyncfusionHelpdesk table. */ DROP TABLE [dbo].[SyncfusionHelpdesk] GO DROP TABLE [dbo].[SyncfusionHelpDeskTicketDetails] GO DROP TABLE [dbo].[SyncfusionHelpDeskTickets] GO |

Figure 60: Update ModuleInfo.cs
In the Client project, open the ModuleInfo.cs file and update the Version property to the following.
Code Listing 14: Update Version
Version = "1.0.1", |
Update the ReleaseVersions property to the following.
Code Listing 15: Update ReleaseVersions
ReleaseVersions = "1.0.0,1.0.1", |
Switch the Syncfusion.Helpdesk solution to Release mode and then rebuild it. This will cause a new, updated NuGet package to be created.
Switch the Syncfusion.Helpdesk solution back to Debug mode and restart the Oqtane site. The Oqtane site will detect the updated NuGet package and run the updated .sql script.

Figure 61: New Tables Created
We can look in the database and confirm the new database tables have been created.

Figure 62: Shared Classes
We will now create classes that will be shared between the Server and Client projects.
In the Shared project, create the following files using the following code.
Code Listing 16: SyncfusionHelpDeskStatus.cs
using System.Collections.Generic; namespace Syncfusion.Helpdesk.Models { public class SyncfusionHelpDeskStatus { public string ID { get; set; } public string Text { get; set; } public static List<SyncfusionHelpDeskStatus> Statuses = new List<SyncfusionHelpDeskStatus>() { new SyncfusionHelpDeskStatus(){ ID= "New", Text= "New" }, new SyncfusionHelpDeskStatus(){ ID= "Open", Text= "Open" }, new SyncfusionHelpDeskStatus(){ ID= "Urgent", Text= "Urgent" }, new SyncfusionHelpDeskStatus(){ ID= "Closed", Text= "Closed" }, }; } } |
Code Listing 17: SyncfusionHelpDeskTicketDetails.cs
using System; using System.ComponentModel.DataAnnotations; using Oqtane.Models; namespace Syncfusion.Helpdesk.Models { public class SyncfusionHelpDeskTicketDetails : IAuditable { [Key] public int HelpDeskTicketDetailId { get; set; } public int HelpDeskTicketId { get; set; } public DateTime TicketDetailDate { get; set; } public string TicketDescription { get; set; } public string CreatedBy { get; set; } public DateTime CreatedOn { get; set; } public string ModifiedBy { get; set; } public DateTime ModifiedOn { get; set; } public virtual SyncfusionHelpDeskTickets HelpDeskTicket { get; set; } } } |
Note: The class in the previous code implements the Oqtane IAuditable interface. Therefore, the Oqtane framework will automatically populate the CreatedBy, CreatedOn, ModifiedBy, and ModifiedOn fields.
Code Listing 18: SyncfusionHelpDeskTickets.cs
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Oqtane.Models; namespace Syncfusion.Helpdesk.Models { public class SyncfusionHelpDeskTickets : IAuditable { public SyncfusionHelpDeskTickets() { SyncfusionHelpDeskTicketDetails = new HashSet<SyncfusionHelpDeskTicketDetails>(); } [Key] public int HelpDeskTicketId { get; set; } public int ModuleId { get; set; } [Required] public string TicketStatus { get; set; } [Required] public DateTime TicketDate { get; set; } [Required] [StringLength(50, MinimumLength = 2, ErrorMessage = "Description must be a minimum of 2 and " + "maximum of 50 characters.")] public string TicketDescription { get; set; } public string CreatedBy { get; set; } public DateTime CreatedOn { get; set; } public string ModifiedBy { get; set; } public DateTime ModifiedOn { get; set; } public virtual ICollection<SyncfusionHelpDeskTicketDetails> SyncfusionHelpDeskTicketDetails { get; set; } } } |
Note: Blazor provides an EditForm control (that will be implemented later in client code) that allows us to validate a form using data annotations. These data annotations are contained in the SyncfusionHelpDeskTickets class.

Figure 63: Repository Code
The repository code directly communicates with the database.
Update the files with the following code.
Oqtane uses Microsoft Entity Framework for database access. The HelpdeskContext class defines our custom tables and allows Entity Framework to connect to them in the database.
To add the new tables we have created, update this class to the following code.
Code Listing 19: HelpdeskContext.cs
using Microsoft.EntityFrameworkCore; using Microsoft.AspNetCore.Http; using Oqtane.Modules; using Oqtane.Repository; using Syncfusion.Helpdesk.Models; namespace Syncfusion.Helpdesk.Repository { public class HelpdeskContext : DBContextBase, IService { public virtual DbSet<Models.SyncfusionHelpDeskTickets> SyncfusionHelpDeskTickets { get; set; } public virtual DbSet<SyncfusionHelpDeskTicketDetails> SyncfusionHelpDeskTicketDetails { get; set; } public HelpdeskContext( ITenantResolver tenantResolver, IHttpContextAccessor accessor) : base(tenantResolver, accessor) { // ContextBase handles multitenant database connections. } } } |
We use an interface called IHelpdeskRepository to define the repository methods that will perform specific operations on the tables in the database (GetSyncfusionHelpDeskTickets, GetSyncfusionHelpDeskTicket, AddSyncfusionHelpDeskTickets, UpdateSyncfusionHelpDeskTickets, and DeleteSyncfusionHelpDeskTickets).
Update this class to the following code.
Code Listing 20: IHelpdeskRepository.cs
using System.Collections.Generic; using System.Linq; using Syncfusion.Helpdesk.Models; namespace Syncfusion.Helpdesk.Repository { public interface IHelpdeskRepository { IQueryable<Models.SyncfusionHelpDeskTickets> GetSyncfusionHelpDeskTickets(int ModuleId); Models.SyncfusionHelpDeskTickets GetSyncfusionHelpDeskTicket(int Id); Models.SyncfusionHelpDeskTickets AddSyncfusionHelpDeskTickets( Models.SyncfusionHelpDeskTickets SyncfusionHelpDeskTicket); Models.SyncfusionHelpDeskTickets UpdateSyncfusionHelpDeskTickets( string UpdateMode, Models.SyncfusionHelpDeskTickets SyncfusionHelpDeskTicket); void DeleteSyncfusionHelpDeskTickets(int Id); } } |
Finally, we implement the repository methods specified in the IHelpdeskRepository interface. Replace all the current code with the following code.
Code Listing 21: HelpdeskRepository.cs
using Microsoft.EntityFrameworkCore; using System.Linq; using System.Collections.Generic; using Oqtane.Modules; using Syncfusion.Helpdesk.Models; using System; namespace Syncfusion.Helpdesk.Repository { public class HelpdeskRepository : IHelpdeskRepository, IService { private readonly HelpdeskContext _db; public HelpdeskRepository(HelpdeskContext context) { _db = context; } } } |
Add the following method to return all the help desk tickets associated with a module instance.
Code Listing 22: GetSyncfusionHelpDeskTickets
public IQueryable<Models.SyncfusionHelpDeskTickets> GetSyncfusionHelpDeskTickets(int ModuleId) { return _db.SyncfusionHelpDeskTickets.Where( item => item.ModuleId == ModuleId); } |
Add the following method to return a single help desk ticket and all its associated help desk ticket details.
Code Listing 23: GetSyncfusionHelpDeskTicket
public Models.SyncfusionHelpDeskTickets GetSyncfusionHelpDeskTicket(int Id) { var HelpDeskTicket = _db.SyncfusionHelpDeskTickets .Where(item => item.HelpDeskTicketId == Id) .Include(x => x.SyncfusionHelpDeskTicketDetails).FirstOrDefault(); // Strip out HelpDeskTicket from SyncfusionHelpDeskTicketDetails // to avoid trying to return self-referencing object. var objDeskTicket = new SyncfusionHelpDeskTickets(); objDeskTicket.HelpDeskTicketId = HelpDeskTicket.HelpDeskTicketId; objDeskTicket.ModuleId = HelpDeskTicket.ModuleId; objDeskTicket.TicketDate = HelpDeskTicket.TicketDate; objDeskTicket.TicketDescription = HelpDeskTicket.TicketDescription; objDeskTicket.TicketStatus = HelpDeskTicket.TicketStatus; objDeskTicket.CreatedBy = HelpDeskTicket.CreatedBy; objDeskTicket.CreatedOn = HelpDeskTicket.CreatedOn; objDeskTicket.ModifiedBy = HelpDeskTicket.ModifiedBy; objDeskTicket.ModifiedOn = HelpDeskTicket.ModifiedOn; objDeskTicket.SyncfusionHelpDeskTicketDetails = new List<SyncfusionHelpDeskTicketDetails>(); foreach (var item in HelpDeskTicket.SyncfusionHelpDeskTicketDetails) { item.HelpDeskTicket = null; objDeskTicket.SyncfusionHelpDeskTicketDetails.Add(item); } return objDeskTicket; } |
Add the following method to add a new help desk ticket.
Code Listing 24: AddSyncfusionHelpDeskTickets
public Models.SyncfusionHelpDeskTickets AddSyncfusionHelpDeskTickets (Models.SyncfusionHelpDeskTickets SyncfusionHelpDeskTicket) { _db.SyncfusionHelpDeskTickets.Add(SyncfusionHelpDeskTicket); _db.SaveChanges(); return SyncfusionHelpDeskTicket; } |
Add the following method to the module to update an existing help desk ticket (and all its associated help desk ticket details).
Code Listing 25: UpdateSyncfusionHelpDeskTickets
public Models.SyncfusionHelpDeskTickets UpdateSyncfusionHelpDeskTickets( string UpdateMode, Models.SyncfusionHelpDeskTickets UpdatedSyncfusionHelpDeskTickets) { // Get the existing record. var ExistingTicket = _db.SyncfusionHelpDeskTickets .Where(x => x.HelpDeskTicketId == UpdatedSyncfusionHelpDeskTickets.HelpDeskTicketId) .FirstOrDefault(); if (ExistingTicket != null) { if (UpdateMode == "Admin") { // Only Admin can update these fields. ExistingTicket.TicketDate = UpdatedSyncfusionHelpDeskTickets.TicketDate; ExistingTicket.TicketDescription = UpdatedSyncfusionHelpDeskTickets.TicketDescription; } ExistingTicket.TicketStatus = UpdatedSyncfusionHelpDeskTickets.TicketStatus; // Insert any new TicketDetails. if (UpdatedSyncfusionHelpDeskTickets .SyncfusionHelpDeskTicketDetails != null) { foreach (var item in UpdatedSyncfusionHelpDeskTickets .SyncfusionHelpDeskTicketDetails) { if (item.HelpDeskTicketDetailId == 0) { // Create New HelpDeskTicketDetails record. SyncfusionHelpDeskTicketDetails newHelpDeskTicketDetails = new SyncfusionHelpDeskTicketDetails(); newHelpDeskTicketDetails.HelpDeskTicketId = UpdatedSyncfusionHelpDeskTickets.HelpDeskTicketId; newHelpDeskTicketDetails.TicketDetailDate = DateTime.Now; newHelpDeskTicketDetails.TicketDescription = item.TicketDescription; _db.SyncfusionHelpDeskTicketDetails .Add(newHelpDeskTicketDetails); _db.SaveChanges(); } } } _db.Entry(ExistingTicket).State = EntityState.Modified; _db.SaveChanges(); }
return ExistingTicket; } |
Finally, add the following method to delete a help desk ticket.
Code Listing 26: DeleteSyncfusionHelpDeskTickets
public void DeleteSyncfusionHelpDeskTickets(int Id) { Models.SyncfusionHelpDeskTickets SyncfusionHelpDeskTicket = _db.SyncfusionHelpDeskTickets.Find(Id); _db.SyncfusionHelpDeskTickets.Remove(SyncfusionHelpDeskTicket); _db.SaveChanges(); } |
We will now create the server-side controller code that will provide the data access methods. This controller will be called by code contained in the Services folder of the Client project.
Code Listing 27: HelpDeskController.cs
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; using System.Collections.Generic; using Microsoft.AspNetCore.Http; using Oqtane.Shared; using Oqtane.Enums; using Oqtane.Infrastructure; using Syncfusion.Helpdesk.Models; using Syncfusion.Helpdesk.Repository; using System.Linq; using System.Threading.Tasks; using Oqtane.Repository; namespace Syncfusion.Helpdesk.Controllers { [Route(ControllerRoutes.Default)] public class HelpdeskController : Controller { private readonly IHelpdeskRepository _HelpDeskRepository; private readonly IUserRepository _users; private readonly ILogManager _logger; protected int _entityId = -1; public HelpdeskController( IHelpdeskRepository HelpDeskRepository, IUserRepository users, ILogManager logger, IHttpContextAccessor accessor) { _HelpDeskRepository = HelpDeskRepository; _users = users; _logger = logger; if (accessor.HttpContext.Request.Query.ContainsKey("entityid")) { _entityId = int.Parse( accessor.HttpContext.Request.Query["entityid"]); } }
} } |
Next, we will add methods to the class. Each method is decorated with an Authorize tag that specifies an access policy. This will ensure the method can be called only by users who have the specified permission.
At the time of publication, the available options are: ViewPage, EditPage, ViewModule, EditModule, ViewFolder, EditFolder, and ListFolder.
Add the following code to implement the method that will allow a user to access their help desk tickets.
Code Listing 28: Get List of SyncfusionHelpDeskTickets
// A non-Administrator can only query their Tickets. // GET: api/<controller>?username=x&entityid=y [HttpGet] [Authorize(Policy = PolicyNames.ViewModule)] public IEnumerable<SyncfusionHelpDeskTickets> Get( string username, string entityid) { // Get User var User = _users.GetUser(this.User.Identity.Name); if (User.Username.ToLower() != username.ToLower()) { return null; } var HelpDeskTickets = _HelpDeskRepository.GetSyncfusionHelpDeskTickets( int.Parse(entityid)) .Where(x => x.CreatedBy == username) .OrderBy(x => x.HelpDeskTicketId) .ToList(); return HelpDeskTickets; } |
Add the following method that will allow a user to retrieve the complete details of a single help desk ticket.
Code Listing 29: Get SyncfusionHelpDeskTickets
// A non-Administrator can only get a Ticket they created. // GET: api/<controller>/1?username=y&entityid=z [HttpGet("{HelpDeskTicketId}")] [Authorize(Policy = PolicyNames.ViewModule)] public SyncfusionHelpDeskTickets Get( string HelpDeskTicketId, string username, string entityid) { // Get User var User = _users.GetUser(this.User.Identity.Name); if (User.Username.ToLower() != username.ToLower()) { return null; } var HelpDeskTicket = _HelpDeskRepository.GetSyncfusionHelpDeskTicket( int.Parse(HelpDeskTicketId)); if (HelpDeskTicket.CreatedBy != User.Username) { return null; } return HelpDeskTicket; } |
Add the following method that will allow a user to create a new help desk ticket.
Code Listing 30: Post SyncfusionHelpDeskTickets
// All users can Post. // POST api/<controller> [HttpPost] [Authorize(Policy = PolicyNames.ViewModule)] public Task Post( [FromBody] Models.SyncfusionHelpDeskTickets SyncfusionHelpDeskTickets) { if (ModelState.IsValid && SyncfusionHelpDeskTickets.ModuleId == _entityId) { // Add a new Help Desk Ticket. SyncfusionHelpDeskTickets = _HelpDeskRepository.AddSyncfusionHelpDeskTickets( SyncfusionHelpDeskTickets); _logger.Log(LogLevel.Information, this, LogFunction.Create, "HelpDesk Added {newSyncfusionHelpDeskTickets}", SyncfusionHelpDeskTickets); } return Task.FromResult(SyncfusionHelpDeskTickets); } |
Add the following method that will allow a user to update an existing help desk ticket.
Code Listing 31: Update SyncfusionHelpDeskTickets
// Only users who created Ticket // can call this method to update Ticket. // POST api/<controller>/1 [HttpPost("{Id}")] [Authorize(Policy = PolicyNames.ViewModule)] public void Post( int Id, [FromBody] Models.SyncfusionHelpDeskTickets UpdateSyncfusionHelpDeskTicket) { // Get User var User = _users.GetUser(this.User.Identity.Name); if (User != null) { // Ensure logged in user is the creator. if (UpdateSyncfusionHelpDeskTicket.CreatedBy.ToLower() == User.Username.ToLower()) { // Update Ticket _HelpDeskRepository.UpdateSyncfusionHelpDeskTickets( "User", UpdateSyncfusionHelpDeskTicket); } } } |

Figure 64: HelpdeskManager.cs
Finally, we will update the code in HelpdeskManager.cs, a class that allows a user to import and export module content.

Figure 65: Import and Export Content
When the module is complete and working again, if we log into the Oqtane site as the host account and navigate to the page containing the module, we can click the Edit pencil icon to enter edit mode. This allows us to select the context menu for the module and access the Import Content and Export Content options.
To enable this functionality, we create import and export methods in a class that implements the IPortable interface.
Replace all the code of the existing HelpdeskManager.cs file with the following code.
Code Listing 32: HelpdeskManager.cs
using System.Collections.Generic; using System.Linq; using System.Text.Json; using Oqtane.Modules; using Oqtane.Models; using Oqtane.Infrastructure; using Oqtane.Repository; using Syncfusion.Helpdesk.Models; using Syncfusion.Helpdesk.Repository; namespace Syncfusion.Helpdesk.Manager { public class HelpdeskManager : IInstallable, IPortable { private IHelpdeskRepository _HelpDeskRepository; private ISqlRepository _sql; public HelpdeskManager( IHelpdeskRepository HelpDeskRepository, ISqlRepository sql) { _HelpDeskRepository = HelpDeskRepository; _sql = sql; } public bool Install(Tenant tenant, string version) { return _sql.ExecuteScript( tenant, GetType().Assembly, "Syncfusion.Helpdesk." + version + ".sql"); } public bool Uninstall(Tenant tenant) { return _sql.ExecuteScript( tenant, GetType().Assembly, "Syncfusion.Helpdesk.Uninstall.sql"); } } } |
Note: This code also implements the Install and Uninstall methods of the IInstallable interface that is called when the module is installed and uninstalled in Oqtane.
To implement the code that will be called when the export functionality is invoked, add the following method to the class.
Code Listing 33: Export Module
public string ExportModule(Module module) { string content = ""; List<Models.SyncfusionHelpDeskTickets> HelpDesks = new List<SyncfusionHelpDeskTickets>(); var AllTickets = _HelpDeskRepository .GetSyncfusionHelpDeskTickets(module.ModuleId).ToList(); foreach (var Ticket in AllTickets) { var HelpDeskTicket = _HelpDeskRepository .GetSyncfusionHelpDeskTicket(Ticket.HelpDeskTicketId); HelpDesks.Add(HelpDeskTicket); } if (HelpDesks != null) { content = JsonSerializer.Serialize(HelpDesks); } return content; } |
To implement the code that will be called when the import functionality is invoked, add the following method to the class.
Code Listing 34: Import Module
public void ImportModule(Module module, string content, string version) { List<Models.SyncfusionHelpDeskTickets> HelpDesks = null; if (!string.IsNullOrEmpty(content)) { HelpDesks = JsonSerializer .Deserialize<List<Models.SyncfusionHelpDeskTickets>>(content); } if (HelpDesks != null) { foreach (var HelpDesk in HelpDesks) { Models.SyncfusionHelpDeskTickets NewHelpDesk = new SyncfusionHelpDeskTickets(); NewHelpDesk.ModuleId = module.ModuleId; NewHelpDesk.TicketDate = HelpDesk.TicketDate; NewHelpDesk.TicketStatus = HelpDesk.TicketStatus; NewHelpDesk.TicketDescription = HelpDesk.TicketDescription; NewHelpDesk.SyncfusionHelpDeskTicketDetails = new List<SyncfusionHelpDeskTicketDetails>(); foreach (var TicketDetail in HelpDesk.SyncfusionHelpDeskTicketDetails) { SyncfusionHelpDeskTicketDetails NewDetail = new SyncfusionHelpDeskTicketDetails(); NewDetail.TicketDetailDate = TicketDetail.TicketDetailDate; NewDetail.ModifiedBy = TicketDetail.ModifiedBy; NewDetail.ModifiedOn = TicketDetail.ModifiedOn; NewDetail.TicketDescription = TicketDetail.TicketDescription; NewHelpDesk.SyncfusionHelpDeskTicketDetails.Add(NewDetail); } _HelpDeskRepository.AddSyncfusionHelpDeskTickets(NewHelpDesk); } } } |
Next, build the solution. The solution should build without errors.