0

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.

2
  • You might have to @using Your.Property.Types.Namespace in order for it to work? Commented Jul 12, 2017 at 20:50
  • To add to @SimonRowe's answer, this would probably work, but doubt it is what you want @Html.EditorFor(model => model.Policies.First().Property, new { htmlAttributes = new { @class = "form-control" } }) Commented Jul 12, 2017 at 21:19

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks @StevePy. This makes a lot of sense. In my case, however, I need to use all the columns in the Policies entity, of which there are many, and four from Companies. My knowledge of creating manual POCOs in an EF database first app is limited, but it seems on first glance to be a lot of overhead. I was seduced by the blog I linked to as I thought this may be a good way to easily access a lot of properties within the View from the auto-generated entities. In any case, I will now study up on creating POCOs and see if this is a way forward for me.
Thanks again for the considered and thoughtful response @StevePy. Lightweight POCOs were definitely the way to go. The code is much more maintainable and all functional logic is in the controller (so good separation of concerns). This was a great learning journey on MVC and EF for me and a good reminder that reliance on the ORM (or any framework for that matter) is not a replacement for good architecture within the application. I very much appreciate your guidance towards the better path.
0

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.

3 Comments

Thanks @SimonRowe. In the blog post Rachel Appel has a Customer entity and a States dictionary entity with the ViewModel. Her code lets her access all the properties from Customer as well as the States dictionary via syntax such as @Html.EditorFor(model => model.Customer.FirstName) and @Html.ValidationMessageFor(model => model.Customer.State). I had the idea that I could adapt what she did to multiple full entities. I did try editing the ViewModel to use single instances of the full entities, but I could only access each entity and not its properties (same as before the edits).
It might help if we knew what you were trying to achieve. Yes her model has those two items but they are all singular to the view model for each view model there is one customer and one state. With your example there are many policies and many trusts. This is fine for viewing data a standard Index view will show you ow to do a displayfor for each of those fields but you are suggesting you want to have an editor for each field of each entity in the collection and razor can't understand how to interpret that. Perhaps a mock up of what you want to achieve would help us help you.
I was hoping that I could make a ViewModel with several entities. And access the properties in the entities within the associated View by using a model.entity.property syntax as I need to mix multiple fields from multiple entities within Create and Edit Views. Now this syntax may not be possible using multiple multi-property entities, and if it's not, I'd be interested in hearing what the acceptable options are. In a perfect world I would probably normalize or even re-architect the db, but that is not an option.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.