views:

553

answers:

4

OK so I have a strongly-typed Customer "Details" view that takes a Customer object Model.

I am using LINQ to SQL and every Customer can have multiple (parking) Spaces.

This is a FK relationship in the database so my LINQ-generated Customer model has a "Spaces" collection. Great!

Here is a code snippet from my CustomerRepository where I iterate through the Customer's parking spaces to delete all payments, spaces and then finally the customer:

public void Delete(Customer customer)
{
    foreach (Space s in customer.Spaces)
        db.Payments.DeleteAllOnSubmit(s.Payments);
    db.Spaces.DeleteAllOnSubmit(customer.Spaces);
    db.Customers.DeleteOnSubmit(customer);
}

Everything works as expected!

Now in my "Details" view I want to populate a table with the Customer's Spaces:

<% foreach (var s in Model.Spaces)
   { %>
    <tr>
        <td><%: s.ID %></td>
        <td><%: s.InstallDate %></td>
        <td><%: s.SpaceType %></td>
        <td><%: s.Meter %></td>
    </tr>
<% } %>

I get the following error:

foreach statement cannot operate on variables of type 'System.Data.Linq.EntitySet' because 'System.Data.Linq.EntitySet' does not contain a public definition for 'GetEnumerator'

Finally, if I add this bit of code to my Customer partial class and use the foreach in the view to iterate through ParkingSpaces everything works as expected:

public IEnumerable<Space> ParkingSpaces
{
    get
    {
        return Spaces.AsEnumerable();
    }
}

The problem here is that I don't want to repeat myself. I was also thinking that I could use a ViewModel to pass a Spaces collection to the View, however LINQ already infers and creates the Spaces property on the Customer model so I think it would be cleanest to just use that.

I am missing something simple or am I approaching this incorrectly?

Thanks!

A: 

There are two ways you can do it, other than your little helper method.

You can inherit an IEnumerable of your class in the page:

<%@ Page Language="C#"
    Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Space>>" %>

<% foreach (var item in Model)
   {

Or you can cast your entity object to an IEnumerable:

<% foreach (var item in Model.Spaces as IEnumerable<Space>)
   {
Robert Harvey
For the first option: As mentioned in my comment to my original post I am not looking to simply list Spaces, but display detailed Customer object model account info where the Customer object model contains an EntitySet of spaces.For the second option: I tried casting in the foreach statement, however I get the following error: "Cannot implicitly convert type 'System.Data.Linq.EntitySet<MyApplication.Models.Space>' to 'object'" -- I'm thinking that using the View Model approach is the way to go, but I don't want to be duplicating myself.
Terminal Frost
+1  A: 
  • First of all using View Models instead of directly accessing DTOs is prefered. (use Automapper for this)

  • Second, Strongly type your views to View Model and in the View Model have an IEnumerable or List passed to the view, then you can iterate through it

Mahesh Velaga
How would I go about creating the View Model without duplicating the collection of Spaces? I am using the NerdDinner tutorial as a template and the example of a View Model is a class which takes a Customer object model and also adds additional properties to supplement the original model which is being passed through. In this case I would end up with an EntitySet of Spaces as well as a separate IEnumerable<Space> collection.Can you point me in the direction of a resource which would explain the proper way to structure this View Model?Thanks!
Terminal Frost
Rule of thumb is that all the info that your view needs will be in the View Model that you pass, so this view model is a tailor made one, and will be filled with data from DTO or DTOs. In case you want to pass a IEnumerable, then the view model will have a IEnumerable in it
Mahesh Velaga
+1  A: 

Sorry if Im a bit late answering this but the correct method of solving your problem is to add an assembly reference to your web.config file so that the view can access the GetEnumerator() method. You can do this using the assembly reference string provided in the page compliation error. eg

Alastair Hopkins
A: 

Just add a reference to System.Data.Linq to your project.

Jeff