views:

1200

answers:

3

Allow me to start with: I am a n00b on ASP.NET MVC. I love it, but I am a n00b.

I am trying to pass "complex" data back from a LINQ query. I understand how to use the data context and then just cast that data when I send it back, but when I do a more complicated LINQ query which returns an anonymous type, things break down.

I saw someone ask a similar question (http://stackoverflow.com/questions/278941/mvc-linq-to-sql-table-join-record-display), and the answer seemed to be to create a new data type to capture the data from the LINQ query. I don't get that I can create a var type in the controller, and access the member fields within the controller, but if I want to pass that var back to my View, I need to create an entire new class for that.

Here’s my Controller code:

var vrGoodResults1 = from records in db.Words
                      group records by records.word1 into g
                      select new
                      {
                          strWord = g.Key,
                          intWordCount = g.Count()
                      };
            ViewData["GoodWords"] = vrGoodResults1;
            return View();

And the View looks like this:

<% foreach (var kvp in (IEnumerable)ViewData["GoodWords"]) %>
<% { %>
        <%= String.Format("{0} was used times", kvp) %> <br />
<% } %>

Which outputs:

{strWord = cool, intWordCount = 2 } was used times
{strWord = educated, intWordCount = 1 } was used times
{strWord = great, intWordCount = 1 } was used times
{strWord = smart, intWordCount = 6 } was used times
{strWord = strong, intWordCount = 2 } was used times
{strWord = super smart, intWordCount = 2 } was used times

So the data is getting to the View, but I cannot refer to the data by the field names I assigned in the LINQ query. When I try dumping kvp.GetType(), I get:

<>f__AnonymousType1`2[System.String,System.Int32]

All I want to do is something along the lines of:

<%= String.Format("{0} was used {1} times", kvp.strWord, kvp.intWordCount) %> <br />

But I am getting a compile error on the kvp.strWord.

error CS1061: 'object' does not contain a definition for 'strWord' and no extension method 'strWord' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)

If I insert the following code into my Controller:

foreach (var kvp in vrGoodResults1)
{
     string strNew = kvp.strWord;
}

I can reference the fields of my variable kvp without a compile error. So something is getting lost when passing from the Controller to the View. Am I forgetting to include something somewhere? Perhaps a “using” or in the “<@ Page” directive, am I forgetting to inherit something?

When you are using LINQ for clear data contexts, you just set the IEnumerable<”datatype”> where “datatype” = your data context type, and you are all good. When you reduce your data set into something new in LINQ, I can't believe that the best answer is to create a new class so that I can use it in my View.

+1  A: 

The best answer here simply is to create a new type. You can do get anonymous types back from object (see here) but it is ugly and brittle. Don't do it!

You could use reflection (kvp.GetType().GetProperty("strWord").GetValue(kvp, null)) - but that also isn't a great idea.

In this case - perhaps use the existing KeyValuePair<string,int> from the original select? Or your own Tuple<T1,T2>?

Marc Gravell
+2  A: 

var is a compiler shortcut for declaring a type in the current scope. It doesn't add any dynamic functionality to the .NET runtime, so code outside the scope sees the object as "System.Object", since that is the most-specific type in the inheritance chain the view code is aware of.

You should create a real class if you want to pass tuple objects around; that's what you had to do before var, so it's not like you're losing anything by having to do it now :)

Rex M
Great answer...thanks! However, it does seem silly to me that you would have to refactor a class should you change your query. Any suggestions on doing query testing?
Brandon Watson
A: 

Don't be afraid of new types. They give lots of other benefits too especially when testing. Use the new property syntax and your class will only be as many lines long as you have properties. You can lose that awful Hungarian notation too. Int and str - yuk

Simon_Weaver
Can you tell I learned how to code in the early 90s? :)
Brandon Watson
@brandon mid 80s for me :-) however i do dislike the way MS convention is to go completely without prefixes. i like to use them for UI controls, such as txtName or cbAcceptTerms for a checkbox. i had your exact same concern myself so i know the feeling - i wonder how 'dynamic' will change the rules
Simon_Weaver