Adding a Movie Kind Field

If we wanted to also keep TV series and mini series in our movie table, we would need another field to store it: MovieKind.

As we didn't add it while creating the Movie table, now we'll write another migration to add it to our database.

Don't modify existing migrations, they won't run again.

Create another migration file under Modules/Common/Migrations/DefaultDB/ DefaultDB_20160519_145500_MovieKind.cs:

using FluentMigrator;

namespace MovieTutorial.Migrations.DefaultDB
{
    [Migration(20160519145500)]
    public class DefaultDB_20160519_145500_MovieKind : Migration
    {
        public override void Up()
        {
            Alter.Table("Movie").InSchema("mov")
                .AddColumn("Kind").AsInt32().NotNullable()
                    .WithDefaultValue(1);
        }

        public override void Down()
        {
        }
    }
}

Declaring a MovieKind Enumeration

Now as we added Kind column to Movie table, we need a set of movie kind values. Let's define it as an enumeration at MovieTutorial.Web/Modules/MovieDB/Movie/MovieKind.cs:

using Serenity.ComponentModel;
using System.ComponentModel;

namespace MovieTutorial.MovieDB
{
    [EnumKey("MovieDB.MovieKind")]
    public enum MovieKind
    {
        [Description("Film")]
        Film = 1,
        [Description("TV Series")]
        TvSeries = 2,
        [Description("Mini Series")]
        MiniSeries = 3
    }
}

Adding Kind Field to MovieRow Entity

As we are not using Sergen anymore, we need to add a mapping in our MovieRow.cs for Kind column manually. Add following property declaration in MovieRow.cs after Runtime property:

[DisplayName("Runtime (mins)")]
public Int32? Runtime
{
    get { return Fields.Runtime[this]; }
    set { Fields.Runtime[this] = value; }
}

[DisplayName("Kind"), NotNull]
public MovieKind? Kind
{
    get { return (MovieKind?)Fields.Kind[this]; }
    set { Fields.Kind[this] = (Int32?)value; }
}

We also need to declare a Int32Field object which is required for Serenity entity system. On the bottom of MovieRow.cs locate RowFields class and modify it to add Kind field after the Runtime field:

public class RowFields : RowFieldsBase
{
    // ...
    public readonly Int32Field Runtime;
    public readonly Int32Field Kind;

    public RowFields()
        : base("[mov].Movie")
    {
        LocalTextPrefix = "MovieDB.Movie";
    }
}

Adding Kind Selection To Our Movie Form

If we build and run our project now, we'll see that there is no change in the Movie form, even if we added Kind field mapping to the MovieRow. This is because, fields shown/edited in the form are controlled by declerations in MovieForm.cs.

Modify MovieForm.cs as below:


namespace MovieTutorial.MovieDB.Forms
{
    // ...
    [FormScript("MovieDB.Movie")]
    [BasedOnRow(typeof(Entities.MovieRow))]
    public class MovieForm
    {
        // ...
        public MovieKind Kind { get; set; }
        public Int32 Runtime { get; set; }
    }
}

Now, build your solution and run it. When you try to edit a movie or add a new one, nothing will happen. This is an expected situation. If you check developer tools console of your browser (F12, inspect element etc.) you'll see such an error:

You might not have this error with ASP.NET Core version as it auto transforms T4

Uncaught Can't find MovieTutorial.MovieDB.MovieKind enum type!

Please Note!

Whenever such a thing happens, e.g. some button not working, you got an empty page, grid etc, please first check browser console for errors, before reporting it.

Why We Had This Error?

This error is caused by MoveKind enumeration not available client side. We should run our T4 templates before executing our program.

Now in Visual Studio, click Build -> Transform All Templates again.

Rebuild your solution and execute it. Now we have a nice dropdown in our form to select movie kind.

Movie Kind Selection

Just build project for ASP.NET Core version, as there is no T4 template

Declaring a Default Value for Movie Kind

As Kind is a required field, we need to fill it in Add Movie dialog, otherwise we'll get a validation error.

But most movies we'll store are feature films, so its default should be this value.

To add a default value for Kind property, add a DefaultValue attribute like this:

[DisplayName("Kind"), NotNull, DefaultValue(MovieKind.Film)]
public MovieKind? Kind
{
    get { return (MovieKind?)Fields.Kind[this]; }
    set { Fields.Kind[this] = (Int32?)value; }
}

Now, in Add Movie dialog, Kind field will come prefilled as Film.