views:

39

answers:

2

I have a main Table, with several "child" tables. TableA and TableAChild1 and TableAChild2.

I have a view which shows the information in TableA, and then has two columns of all items in TableAChild1 and TableAChild2 respectivly, they are rendered with Partial views.

Both child tables have a bit field for VisibleToAll, and depending on user role, I'd like to either display all related rows, or related rows where VisibleToAll = true.

This code, feels like it should be in the controller, but I'm not sure how it would look, because as it stands, the controller (limmited version) looks like this:

return View("TableADetailView", repos.GetTableA(id));

Would something like this be even work, and would it be bad what if my DataContext gets submitted, would that delete all the rows that have VisibleToAll == false?

var tblA = repos.GetTableA(id);
tblA.TableAChild1 = tblA.TableAChild1.Where(tmp => tmp.VisibleToAll == true);
tblA.TableAChild2 = tblA.TableAChild2.Where(tmp => tmp.VisibleToAll == true);
return View("TableADetailView", tblA);

It would also be simple to add that logic to the RendarPartial call from the main view:

<% Html.RenderPartial("TableAChild1", Model.TableAChild1.Where(tmp => tmp.VisibleToAll == true); %>
+1  A: 

It's a subject of great debate I think. To me there are two clear routes:

Deferred Execution Route Never use ToList, always use AsQueryable in controllers. This means only the data that is necessary for presentation is retrieved and only when it is needed in the View once ToList etc. are called.

Presentation Shows Models Prepare data for presentation using Model classes or results that are already filtered. Strongly type your View to the expected format.

I prefer deferred execution myself, though in a pure MVC structure the Controller should worry about getting the information and the View should only display the Mode.

Regardless, make sure you are using AsQueryable with your Repository.

Nissan Fan
My repository is returning IQueryable items. However, in this case, since I'm displaying one record and sub-records, I'm not sure how the deferred execution would work, since I already called SingleOrDefault() in the controller on the parent table.
Nate Bross
+1 for being reasonable and not preaching about view models.
jfar
+2  A: 

For me there is no question. Your controller should never return IQueryable to a view. Views should not have the logic to perform such filtering, so this has to be done in the controller or something that the controller calls into. If you views have such logic they are too smart! I know it might sound like I'm "preaching about view models" (as jfar commented in previous post) or best practices but those are defined for a reason. Views with too much logic are way too hard to maintain, you might as well just use ASP.NET (or classic ASP) for that matter.

I honestly don't even think that your controllers should be using IQueryable themselves for this. This logic should be contained in a separate layer which returns lists back to the controller. The problem with using IQueryable everywhere is because doing so will work when things are in the same layer, but if you were to place your data access behind a WCF service your entire app would blow up. Your .Where statements in the Views as well as controllers would them complain about not being able to access the context because the context is no longer available.

Sayed Ibrahim Hashimi