Adding Primary and Gallery Images
To add a primary image and multiple gallery images to both Movie and Person records, need to start with a migration:
using FluentMigrator;
namespace MovieTutorial.Migrations.DefaultDB
{
[Migration(20221122_115100)]
public class DefaultDB_20221122_115100_PersonMovieImages : AutoReversingMigration
{
public override void Up()
{
Alter.Table("Person").InSchema("mov")
.AddColumn("PrimaryImage").AsString(100).Nullable()
.AddColumn("GalleryImages").AsString(int.MaxValue).Nullable();
Alter.Table("Movie").InSchema("mov")
.AddColumn("PrimaryImage").AsString(100).Nullable()
.AddColumn("GalleryImages").AsString(int.MaxValue).Nullable();
}
}
}
Then modify MovieRow.cs and PersonRow.cs:
namespace MovieTutorial.MovieDB
{
// ...
public sealed class PersonRow : Row<PersonRow.RowFields>, IIdRow, INameRow
{
// ...
[DisplayName("Primary Image"), Size(100),
ImageUploadEditor(FilenameFormat = "Person/PrimaryImage/~")]
public string PrimaryImage
{
get => fields.PrimaryImage[this];
set => fields.PrimaryImage[this] = value;
}
[DisplayName("Gallery Images"),
MultipleImageUploadEditor(FilenameFormat = "Person/GalleryImages/~")]
public string GalleryImages
{
get => fields.GalleryImages[this];
set => fields.GalleryImages[this] = value;
}
public class RowFields : RowFieldsBase
{
// ...
public StringField PrimaryImage;
public StringField GalleryImages;
}
}
}
namespace MovieTutorial.MovieDB
{
// ...
public sealed class MovieRow : Row<MoviesRow.RowFields>, IIdRow, INameRow
{
// ...
[DisplayName("Primary Image"), Size(100),
ImageUploadEditor(FilenameFormat = "Movie/PrimaryImage/~")]
public string PrimaryImage
{
get => fields.PrimaryImage[this];
set => fields.PrimaryImage[this] = value;
}
[DisplayName("Gallery Images"),
MultipleImageUploadEditor(FilenameFormat = "Movie/GalleryImages/~")]
public string GalleryImages
{
get => fields.GalleryImages[this];
set => fields.GalleryImages[this] = value;
}
public class RowFields : RowFieldsBase
{
// ...
public StringField PrimaryImage;
public StringField GalleryImages;
}
}
}
Here we specify that these fields will be handled by ImageUploadEditor and MultipleImageUploadEditor types.
FilenameFormat specifies the naming of uploaded files. For example, Person primary image will be uploaded to a folder under App_Data/upload/Person/PrimaryImage/.
You may change upload root (App_Data/upload) to anything you like by modifying UploadSettings appSettings key in appsetttings.json.
~
at the end of FilenameFormat is a shortcut for the automatic naming scheme {1:00000}/{0:00000000}_{2}
.
Here, parameter {0} is replaced with identity of the record, e.g. PersonID.
Parameter {1} is identity / 1000. This is useful to limit number of files that is stored in one directory.
Parameter {2} is a unique string like 6l55nk6v2tiyi, which is used to generate a new file name on every upload. This helps to avoid problems caused by caching on client side.
It also provides some security so file names can't be known without having a link.
Thus, a file we upload for person primary image will be located at a path like this:
> App_Data\upload\Person\PrimaryImage\00000\00000001_6l55nk6v2tiyi.jpg
You don't have to follow this naming scheme. You can specify your own format like
PersonPrimaryImage_{0}_{2}
.
Next step is to add these fields to forms (MovieForm.cs and PersonForm.cs):
namespace MovieTutorial.MovieDB.Forms
{
//...
public class PersonForm
{
[Tab("Person")]
public string FirstName { get; set; }
public string Lastname { get; set; }
public string PrimaryImage { get; set; }
public string GalleryImages { get; set; }
public DateTime BirthDate { get; set; }
public string BirthPlace { get; set; }
public Gender Gender { get; set; }
public int Height { get; set; }
[Tab("Movies"), IgnoreName, PersonMovieGrid, LabelWidth("0")]
public string MoviesGrid { get; set; }
}
}
namespace MovieTutorial.MovieDB.Forms
{
//...
public class MovieForm
{
public string Title { get; set; }
[TextAreaEditor(Rows = 3)]
public string Description { get; set; }
[MovieCastEditor]
public List<MovieCastRow> CastList { get; set; }
public string PrimaryImage { get; set; }
public string GalleryImages { get; set; }
[TextAreaEditor(Rows = 8)]
public string Storyline { get; set; }
public int Year { get; set; }
public DateTime ReleaseDate { get; set; }
public int Runtime { get; set; }
public List<int> GenreList { get; set; }
public MovieKind Kind { get; set; }
}
}
I also modified Person dialog css a bit to have more space:
.s-MovieDB-PersonDialog .s-PersonMovieGrid > .grid-container {
height: 500px;
}
This is what we get now:
ImageUploadEditor stores file name directly in a string field, while MultipleImageUpload editor stores file names in a string field with JSON array format.
Use form as a panel
As you can see in previous picture we have too much properties now. Lets turn this form to a panel.
Add panel decorator to PersonDialog.ts:
//...
@Decorators.registerClass("MovieTutorial.MovieDB.PersonDialog")
@Decorators.panel()
export class PersonDialog extends EntityDialog<PersonRow, any> {
//...
}
Removing Northwind and Other Samples
As i think our project has reached a good state, i'm now going to remove Northwind and other samples from MovieTutorial project.
See following how-to topic: