joeschwa
joeschwa

Reputation: 3175

Access Entity Framework ViewModel properties in View using Lambda Expressions

I was intrigued by this Rachel Appel blog post that has a View that references a ViewModel, and within the View is able to access the properties across the ViewModel's multiple entities using Lambda expressions with this syntax:

@Html.EditorFor(model => model.ViewModelEntityName.Property)

I was able to access the individual ViewModel entities, but not the properties of those entities. Here is my code:

ViewModel

public class PoliciesTrustsViewModel
{
    public ICollection<Insurance> Policies { get; set; } //model in partial class generated by EF database first      
    public ICollection<Companies> Trusts { get; set; } //model in partial class generated by EF database first

    public PoliciesTrustsViewModel(ICollection<Insurance> policies, ICollection<Companies> trusts)
    {
        Policies = policies;

        Trusts = trusts;
    }

Controller

public ActionResult Create()
{
        ICollection<Insurance> policies = db.Insurance.ToList();
        ICollection<Companies> trusts = db.Companies.ToList();

        var myViewModel = new ViewModels.PoliciesTrustsViewModel(policies, trusts);

        return View(myViewModel);
}

View

I set the model reference to the ViewModel:

@model IEnumerable<TrustsInsurance.ViewModels.PoliciesTrustsViewModel>

Lambda expressions will accept the entity name but will not allow the properties within an individual entity. So

@Html.EditorFor(model => model.Policies, new { htmlAttributes = new { @class = "form-control" } })

is allowable, but

@Html.EditorFor(model => model.Policies.Property, new { htmlAttributes = new { @class = "form-control" } })

yields a "does not contain a definition" error. I tried using a @foreach (var item in Model) loop in razor as well as a number of different casts, but no sale. So how can one access properties across multiple models using lambda expressions? Any nudge in the right direction would be greatly appreciated.

Upvotes: 0

Views: 391

Answers (2)

Steve Py
Steve Py

Reputation: 34773

I'd avoid embedding EF entities in your ViewModels. As per points:

  • Put only data that you’ll render in the ViewModel.
  • The view should direct the properties of the ViewModel, this way it fits better for rendering and maintenance.

Relational data is fine, but unless you need "everything" that constitutes a related entity, you're much better off simplifying the data as POCOs. Passing entity references around generally leads to pain. Lazy loading out of the dbContext Scope, or the expense of eager-loading "everything" in case it might be needed down the road, re-associating entities to dbContexts on submit.. More mess than it's worth.

For instance, given a view model where I want a list of things like Policies and Trusts(Companies) if I only care about the FK and a pretty name, my ViewModel is going to contain a List<PolicySummary> and List<CompanySummary> where PolicySummary is a POCO containing the PolicyId and DisplayName. CompanySummary might have CompanyId, CompanyName, and Address. (as a formatted mailing address block) These POCOs are lightweight, and can most often be saturated in a simple .Select() statement. On the round trip you have the IDs to retrieve from the relevant dbContext to associate in your operation.

Upvotes: 1

Simon Rowe
Simon Rowe

Reputation: 11

I only had a quick scan of the blog but the most obvious difference is the example in the blog has a single instance of Customer in the ViewModel but your example above includes two ICollections.

As a consequence Razor is trying to find an editor not for one Policy.Property but for a whole collection of them, and by the looks of things failing.

Try the same logic but with a single instance of Policy and Trust in your ViewModel and you should get a rendered view.

If you need to have the ability to edit collections you will need to do some googling. You should find examples on SO to help you out.

Upvotes: 0

Related Questions