Skip to content
Dmitry Savchenko edited this page Jul 15, 2016 · 10 revisions

After the actions described above, we come to the most interesting part – code writing implementing the CRUD (create, read, update, delete) functionality of an application. To begin this process, create an entity class that will map to the DB. In our case, this is Human.cs that we add to the Example.Domain -> Persistences folder.

Human.cs
``` namespace Example.Domain { #region << Using >>
using System;
using Incoding.Data;

#endregion

public class Human : IncEntityBase
{
    #region Properties

    public virtual DateTime Birthday { get; set; }

    public virtual string FirstName { get; set; }

    public new virtual string Id { get; set; }

    public virtual string LastName { get; set; }

    public virtual Sex Sex { get; set; }

    #endregion

    #region Nested Classes

    public class Map : NHibernateEntityMap<Human>
    {
        #region Constructors

        protected Map()
        {
            IdGenerateByGuid(r => r.Id);
            MapEscaping(r => r.FirstName);
            MapEscaping(r => r.LastName);
            MapEscaping(r => r.Birthday);
            MapEscaping(r => r.Sex);
        }

        #endregion
    }

    #endregion
}

public enum Sex
{
    Male = 1,

    Female = 2
}

}

<p>Our class contains several fields where we will write data and Nested Class Map.</p>
<p>We can now add commands and queries, which are responsible for realization of the CRUD operations. The first command will be responsible for adding a new or change an existing record of the <em>Human</em> type.  The command is quite simple: we either get an entity on a Repository using the key (Id) or, if no entity exist, we create a new one. Both of these entities get the values specified in the properties of the <em>AddOrEditHumanCommand</em> class. Add <strong>Example.Domain -&gt; Operations -&gt; AddOrEditHumanCommand.cs to the project.</strong></p>
<h6>AddOrEditHumanCommand.cs</h6>

namespace Example.Domain { #region << Using >>

using System;
using FluentValidation;
using Incoding.CQRS;
using Incoding.Extensions;

#endregion

public class AddOrEditHumanCommand : CommandBase
{
    #region Properties

    public DateTime BirthDay { get; set; }

    public string FirstName { get; set; }

    public string Id { get; set; }

    public string LastName { get; set; }

    public Sex Sex { get; set; }

    #endregion

    public override void Execute()
    {
        var human = Repository.GetById<Human>(Id) ?? new Human();

        human.FirstName = FirstName;
        human.LastName = LastName;
        human.Birthday = BirthDay;
        human.Sex = Sex;

        Repository.SaveOrUpdate(human);
    }
}

}

<p>The Read command is the second part of the CRUD. This is a request for reading entities from the DB. Add the file <strong>Example.Domain -&gt; Operations -&gt; GetPeopleQuery.cs</strong>.</p>
<h6>GetPeopleQuery.cs</h6>

namespace Example.Domain { #region << Using >>

using System.Collections.Generic;
using System.Linq;
using Incoding.CQRS;

#endregion

public class GetPeopleQuery : QueryBase<List<GetPeopleQuery.Response>>
{
    #region Properties

    public string Keyword { get; set; }

    #endregion

    #region Nested Classes

    public class Response
    {
        #region Properties

        public string Birthday { get; set; }

        public string FirstName { get; set; }

        public string Id { get; set; }

        public string LastName { get; set; }

        public string Sex { get; set; }

        #endregion
    }

    #endregion

    protected override List<Response> ExecuteResult()
    {
        return Repository.Query<Human>()
                         .Select(human => new Response
                                                {
                                                     Id = human.Id,
                                                     Birthday = human.Birthday.ToShortDateString(),
                                                     FirstName = human.FirstName,
                                                     LastName = human.LastName,
                                                     Sex = human.Sex.ToString()
                                                 }).ToList();
    }
}

}

<p>The Delete command is the remaining part of the CRUD. The command deletes records from the DB using the key (Id). Add the file <strong>Example.Domain -&gt; Operations -&gt; DeleteHumanCommand.cs</strong>.</p>
<h6>DeleteHumanCommand.cs</h6>

namespace Example.Domain { #region << Using >>

using Incoding.CQRS;

#endregion

public class DeleteHumanCommand : CommandBase
{
    #region Properties

    public string HumanId { get; set; }

    #endregion

    public override void Execute()
    {
        Repository.Delete<Human>(HumanId);
    }
}

}

<p>In order to populate the DB with initial data, add the file <strong>Example.Domain -&gt; InitPeople.cs </strong>that is derived from the <em>ISetUP</em> interface.</p>
<h6 style="text-align: justify;">ISetup</h6>

using System;

namespace Incoding.CQRS { public interface ISetUp : IDisposable { int GetOrder();

void Execute();

} }

<p>All the class instances from the <em>ISetUp</em> are registered with IoC in the Bootstrapper.cs (see Introduction) and run (<em>public void Execute()</em>) in order (<em>public int GetOrder()</em>).</p>
<h6>InitPeople.cs</h6>

namespace Example.Domain { #region << Using >>

using System;
using Incoding.Block.IoC;
using Incoding.CQRS;
using NHibernate.Util;

#endregion

public class InitPeople : ISetUp
{
    public void Dispose() { }

    public int GetOrder()
    {
        return 0;
    }

    public void Execute()
    {
        var dispatcher = IoCFactory.Instance.TryResolve<IDispatcher>();
        
        if (dispatcher.Query(new GetEntitiesQuery<Human>()).Any())
            return;

        dispatcher.Push(new AddOrEditHumanCommand
                            {
                                    FirstName = "Hellen",
                                    LastName = "Jonson",
                                    BirthDay = Convert.ToDateTime("06/05/1985"),
                                    Sex = Sex.Female
                            });
        dispatcher.Push(new AddOrEditHumanCommand
                            {
                                    FirstName = "John",
                                    LastName = "Carlson",
                                    BirthDay = Convert.ToDateTime("06/07/1985"),
                                    Sex = Sex.Male
                            });
    }
}

}

<p>The back-end implementation of the CRUD is ready. Now it is time to add a user code. As in the case of the back end, we begin the implementation with creating/editing a record. Add the file<strong> Example.UI -&gt; Views -&gt; Home -&gt; AddOrEditHuman.cshtml.</strong></p>
<h6>AddOrEditHuman.cshtml</h6>

@using Example.Domain @using Incoding.MetaLanguageContrib @using Incoding.MvcContrib @model Example.Domain.AddOrEditHumanCommand @using (Html.When(JqueryBind.Submit) .PreventDefault() .Submit() .OnSuccess(dsl => { dsl.WithId("PeopleTable").Core().Trigger.Incoding(); dsl.WithId("dialog").JqueryUI().Dialog.Close(); }) .OnError(dsl => dsl.Self().Core().Form.Validation.Refresh()) .AsHtmlAttributes(new { action = Url.Dispatcher().Push(new AddOrEditHumanCommand()), enctype = "multipart/form-data", method = "POST" }) .ToBeginTag(Html, HtmlTag.Form)) {

@Html.HiddenFor(r => r.Id) @Html.ForGroup(r => r.FirstName).TextBox(control => control.Label.Name = "First name")
@Html.ForGroup(r => r.LastName).TextBox(control => control.Label.Name = "Last name")
@Html.ForGroup(r => r.BirthDay).TextBox(control => control.Label.Name = "Birthday")
@Html.ForGroup(r => r.Sex).DropDown(control => control.Input.Data = typeof(Sex).ToSelectList())
<div>
    <input type="submit" value="Save"/>
    @(Html.When(JqueryBind.Click)
          .PreventDefault()
          .StopPropagation()
          .Direct()
          .OnSuccess(dsl => { dsl.WithId("dialog").JqueryUI().Dialog.Close(); })
          .AsHtmlAttributes()
          .ToButton("Cancel"))
</div>

}

<p>The IML-code creates the standard HTML form and works with <em>AddOrEditHumanCommand</em>, sending the appropriate Ajax query to the server.</p>
<p>Then comes the template for data loading through the GetPeopleQuery. There is a description of the table that will be responsible not only for data output, but also for record deletion and editing: add the file <strong>Example.UI -&gt; Views -&gt; Home -&gt; HumanTmpl.cshtml.</strong></p>
<h6>HumanTmpl.cshtml</h6>

@using Example.Domain @using Incoding.MetaLanguageContrib @using Incoding.MvcContrib @{ using (var template = Html.Incoding().Template<GetPeopleQuery.Response>()) {

@using (var each = template.ForEach()) {
First name Last name Birthday Sex
@each.For(r => r.FirstName) @each.For(r => r.LastName) @each.For(r => r.Birthday) @each.For(r => r.Sex) @(Html.When(JqueryBind.Click) .AjaxGet(Url.Dispatcher().Model(new { Id = each.For(r => r.Id), FirstName = each.For(r => r.FirstName), LastName = each.For(r => r.LastName), BirthDay = each.For(r => r.Birthday), Sex = each.For(r => r.Sex) }) .AsView("~/Views/Home/AddOrEditHuman.cshtml")) .OnSuccess(dsl => dsl.WithId("dialog").Behaviors(inDsl => { inDsl.Core().Insert.Html(); inDsl.JqueryUI().Dialog.Open(option => { option.Resizable = false; option.Title = "Edit human"; }); })) .AsHtmlAttributes() .ToButton("Edit"))
                    @(Html.When(JqueryBind.Click)
                          .AjaxPost(Url.Dispatcher().Push(new DeleteHumanCommand() { HumanId = each.For(r => r.Id) }))
                          .OnSuccess(dsl => dsl.WithId("PeopleTable").Core().Trigger.Incoding())
                          .AsHtmlAttributes()
                          .ToButton("Delete"))
                </td>
            </tr>
        }
        </tbody>
    </table>
}

}

<p>Thus, it remains to change the start page so that during its loading AJAX query is transmitted to the server for obtaining data from the <em>GetPeopleQuery</em> and mapping of data using <em>HumanTmpl</em>: change the file <strong>Example.UI -&gt; Views -&gt; Home -&gt; Index.cshtml</strong> so that it looks as follows.</p>
<h6>Index.cshtml</h6>

@using Example.Domain @using Incoding.MetaLanguageContrib @using Incoding.MvcContrib @{ Layout = "~/Views/Shared/_Layout.cshtml"; }

@(Html.When(JqueryBind.InitIncoding) .AjaxGet(Url.Dispatcher().Query(new GetPeopleQuery()).AsJson()) .OnSuccess(dsl => dsl.Self().Core().Insert.WithTemplateByUrl(Url.Dispatcher().AsView("~/Views/Home/HumanTmpl.cshtml")).Html()) .AsHtmlAttributes(new { id = "PeopleTable" }) .ToDiv())

@(Html.When(JqueryBind.Click) .AjaxGet(Url.Dispatcher().AsView("~/Views/Home/AddOrEditHuman.cshtml")) .OnSuccess(dsl => dsl.WithId("dialog").Behaviors(inDsl => { inDsl.Core().Insert.Html(); inDsl.JqueryUI().Dialog.Open(option => { option.Resizable = false; option.Title = "Add human"; }); })) .AsHtmlAttributes() .ToButton("Add new human"))

<p>In real-world applications, validation of input form data is one of the most frequent task. Therefore, we add data validation on the adding/editing form of the Human entity. First, we need to add a server code. Add the following code in <em>AddOrEditHumanCommand</em> as a nested class:</p>

#region Nested Classes

public class Validator : AbstractValidator { #region Constructors

public Validator()
{
    RuleFor(r => r.FirstName).NotEmpty();
    RuleFor(r => r.LastName).NotEmpty();
}

#endregion

}

#endregion

<p>On the <em>AddOrEditHuman.cshtml</em> form, we used constructs like this:</p>

@Html.ForGroup()

<p>It is therefore not necessary to add</p>

@Html.ValidationMessageFor()

<p>for the fields - <em>ForGroup()</em> will do it.</p>
<p>So we have written the application code that implements the CRUD functionality for one DB entity.</p>
<br/>
<ul>
<li><a href="/IncodingSoftware/get-started/wiki/3.-Setting-up-a-DB-connection">Previous</a></li>
<li><a href="/IncodingSoftware/get-started/wiki/5.-Specifications:-data-filters">Next</a></li>
</ul>
Clone this wiki locally