c# – Code First with Complex Types, when Scaffolding the properties of Complex Types are not found in the views

Question:

I'm following Sergey Barskiy's presentation at http://www.youtube.com/watch?v=l3WzYZsN0gU , where he demonstrates the Entity FrameWork approach with Code First.

I loved it, but I had a problem.

In the presentation, he demonstrates that I can use Complex Types for the properties of my POCO class, and how tables are generated in the database. Success so far. His presentation goes there.

But then I couldn't get these complex types to be created in the views when doing Scaffolding with the class. And that's my problem.

I created two POCO classes called Company and Person, both have an Address property and an Audit property (which are complex types).

Below my POCO classes:

public class Empresa
{
    public int EmpresaId { get; set; }

    public string Nome { get; set; }

    public Endereco Endereco { get; set; }

    public Auditoria Auditoria { get; set; }

    public virtual ICollection<Pessoa> Pessoas { get; set; }
}

   public class Pessoa
   {
        public int PessoaId { get; set; }

        public String Nome { get; set; }

        public DateTime DataNascimento { get; set; }

        public Endereco Endereco { get; set; }

        public Auditoria Auditoria { get; set; }

        public int EmpresaId { get; set; }

        public Empresa Empresa { get; set; }
    }

public class Endereco
{
    public string Rua { get; set; }
    public string Cidade { get; set; }
    public string UF { get; set; }
}

public class Auditoria
{
    public string CriadoPor { get; set; }
    public DateTime CriadoEm { get; set; }
    public string ModificadoPor { get; set; }
    public DateTime? ModificadoEm { get; set; }
}

The problem was when doing the Scaffolding. I went to create a Controller for the Company, I used the MVC 5 Controller with views, using Entity Framework , and I chose the Empresa class as Model Class. However, when generating the views they do not have the properties of the Address and Audit classes:

Below the created view Create.cshtml:

@model CodeFirstSample.Data.Empresa

@{
    ViewBag.Title = "Create";
}

<h2>Create</h2>


@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>Empresa</h4>
        <hr />
        @Html.ValidationSummary(true)

        <div class="form-group">
            @Html.LabelFor(model => model.Nome, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Nome)
                @Html.ValidationMessageFor(model => model.Nome)
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

To include the address and the audit I had to add it by hand, as shown below, where I added the Street of the Address property and the CriePor of the Audit property:

@model CodeFirstSample.Data.Empresa

@{
    ViewBag.Title = "Create";

}

<h2>Create</h2>


@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>Empresa</h4>
        <hr />
        @Html.ValidationSummary(true)

        <div class="form-group">
            @Html.LabelFor(model => model.Nome, new { @class="label-control col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Nome, new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.Nome)
            </div>
        </div>
        <div class="form-group">
        @Html.LabelFor(model => model.Endereco.Rua, new { @class="label-control col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Endereco)
            @Html.ValidationMessageFor(model => model.Endereco.Rua)
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Auditoria.CriadoPor, new { @class="label-control col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Auditoria.CriadoPor)
            @Html.ValidationMessageFor(model => model.Auditoria.CriadoPor)
        </div>
    </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

I managed to solve it by hand, but is there any way for the T4 template to already include the Address and Audit properties?

Answer:

Change your class like this:

public class Empresa
    {
        public int EmpresaId { get; set; }

        public string Nome { get; set; }

        public int EnderecoID { get; set; }

        public virtual Endereco Endereco { get; set; }

        public int AuditoriaID {get; set}

        public virtual Auditoria Auditoria { get; set; }

        public virtual ICollection<Pessoa> Pessoas { get; set; }
    }

When performing the scaffolding it will find the property AddressID and will automatically create a foreign key for this field, by default every property with a class name ending with ID it will try to create a foreign key [classeID].

The virtual property is to actually be able to browse the object's properties.

Adjust the other classes try scaffolding again, a dropdown list will be generated in the view. for more information I recommend: Steven Sanderson's blog It's about MVC3 but the whole base is the same.

Scroll to Top