Relation Scaffolding for MVC

19 May

I have been using MVC for multiple projects, and one of the really powerful tool is the ability to Scaffold your project from templates. The one I like the most is when creating an admin page, you can generate the full CRUD (Create/Read/Update/Delete) in just a few clicks for Entity Framework.

However, there is one problem with scaffolding provided by Microsoft: it does not handle the relations between models. This is why I have been working on a NuGet package to handle this.

Installation

Simply run “Install-Package RelationScaffolding” on your project to get started. This will install the required DLLs, a few files in /Shared/DisplayTemplates and /Shared/EditorTemplates and one file in /Scripts/relation.js

Model example

We will start with a basic example of relations. Let’s use a Student/Teacher/Course example:

Most of the classes come with an “Id” and a “Name”. These are the main property we will use to link and display them.

Make a relation

To connect one model with another one, we use the [Relation] attribute on the desired property:
[RelationScaffolding.Relation]
public virtual Teacher Teacher { get; set; }

This indicates to use the DisplayTemplates or EditorTemplates that have been installed with the NuGet package. You can read more about templates on Hanselman’s post.

Relations work also with collections:
[RelationScaffolding.Relation]
public virtual ICollection<Course> Courses { get; set; }

Which property to display

To indicate what to show when using a template, we will use the following attribute:
[RelationScaffolding.RelationDisplay]
public string Name { get; set; }

Using the template

By default, the scaffolding does not output the properties that are linked to another model. You can add them in your CSHTML as such:

Read
Teacher: @Html.DisplayFor(m => m.Course.Teacher)
Courses: @Html.DisplayFor(m => m.Teacher.Courses)

Write
Teacher: @Html.EditorFor(m => m.Course.Teacher, new { List = Model.AvailableTeachers })
Courses: @Html.EditorFor(m => m.Teacher.Courses, new { List = Model.AvailableCourses })

Now you might notice a custom attribute when using the write template: List.

By providing a list with all available items, the combo box or the checkbox list will contain the possible selectable options.

Template used with DisplayFor

Template used with DisplayFor

Template used with EditorFor

Template used with EditorFor

Customize edit

Default value in combo box

Common scenarios are to write a default value with no ID in a combo box. To do so, use the attribute RelationSingle instead of the attribute Relation. Then use the following parameter:
[RelationScaffolding.RelationSingle(Empty = "Select a teacher.")]
public virtual Teacher Teacher { get; set; }

scaffolding-empty

Different name property

When displaying the combo box, you might want to tweak the name where the selection is being written. Let’s say you have the following properties:
public int TeacherId { get; set; }
public virtual Teacher Teacher { get; set; }

Entity Framework will understand that TeacherId is actually mapped to your database. It also loads the entity directly into the virtual property matching the name.

By using the EditorTemplate on Teacher, the name will be Teacher.Id. If you want to use the TeacherId property instead, use “ShortcutProperty = true” as such:

@Html.EditorFor(m => m.Course.Teacher, new { ShortcutProperty = true })

scaffolding-shortcut

If your property key does not happen to follow this convention, you can use PropertyName = "TeacherId" instead.

Adding to a collection

If you want to be able to add to a collection, you can use the attribute RelationMultiple instead of the Relation attribute. Set the property CanAdd to true. A text box will be available under the checkbox list. To indicate which property should be used when creating that new object, use the attribute RelationEdit.

See an example on Course.cs

scaffolding-canadd

More to come!

I have other ideas on how to make this package easier to use.

  • Model Binder
  • Make “CanAdd” more generic
  • Support Many 2 Many
  • Add a new Scaffolding template T4
  • Better support of styles
  • I18n
  • Unit Tests

If you like this project, don’t hesitate to participate on GitHub!

Jean-Sébastien Goupil (11 Posts)

Web Architect Consultant - Passionate about web projects! Expert in barcodes, automation, and JavaScript

  • Nice idea JS, I had to build some CRUD pages in the past and this would have been helpful.

    Cheers!

  • adi silagy

    Very nice article! But I prefer to build ViewModels on top of the Models / Entities created by the entity framework. In my opinion it gives more flexibility which is necessary in complicated projects, and it gives another layer of security.