How would I covert this query to inline sql or a stored procedure?
var a = from arow in context.post
where arow.post_id == id && arow.post_isdeleted == false
select new
{
arow.post_id,
PostComments = from c in context.comment
where c.CommentPostID == arow.post_id
select new
{
c.id,
c.title
}
}
List<PostType> pt;
foreach (var s in a)
{
pt = new PostType();
pt.PostID = s.post_id;
//how would I use ADO.NET to put this in a custom class?
foreach(var ctl in s.PostComments)
{
ctl.Title = ctl.title;
pt.CommentT.Add(ctl);
}
ptl.Add(pt);
}
Once the inline query has been executed how would I put the information in a custom class? PostComments is a subquery — so how would I use ADO.NET to put it in a custom class?
Short Explanation
It seems the portion of your question that may seem tricky is how to populate a custom class in the same fashion that the LINQ to SQL (“L2S” from here on out) query does for the anonymous class.
Based on your
foreachloop I am guessing your custom classes are similar to these:The LINQ query should be equivalent to this T-SQL statement:
Unlike the L2S version (see the Detailed Explanation section below for more info), this statement returns a flattened result with each row containing a
P.post_id,C.id, andC.title. If yourPostTypeclass represented an entry in the same way this would’ve been easily solved (I’m not advocating such a design; I’m merely commenting on how the design alters how it gets populated). The hierarchical relationship in the classes changes things.Also, your code showed a
List<PostType>but a list is not required since there will always be onePostTypebecause you’re filtering onpost_id. If that condition is removed, then you might get multiple matches with different PostIds where the other conditions are satisfied. If that’s the case the code below would need to change.That said, let’s jump into some ADO.NET and populate the classes using a SqlDataReader.
That should cover your scenario. However, for a much more detailed answer, keep reading!
Detailed Explanation (aka “Teach a man to fish…”)
Let’s say you couldn’t figure out how to get the equivalent SQL statement. While there are different ways to do so, I will concentrate on the fact that you are using L2S and explore some related options.
Step 1: Converting the LINQ query to SQL (by “cheating”)
You’re in luck since there’s a shortcut. Converting your existing LINQ expression to SQL is a slightly more convenient situation to be in than going backwards and translating SQL to LINQ.
You can get the translated T-SQL statement from your code by using either of these DataContext options:
NOTE: I did say this was a shortcut. Knowledge of SQL is good to know, and to be clear I am not suggesting the use of generated output blindly. Granted, the SQL may differ from what you expect sometimes, nonetheless it provides a decent starting point. You may tweak it if needed.
Use either of these methods and copy the result – you’ll need it for Step 2.
Example DataContext.GetCommand() usage:
To get the result either set a breakpoint and copy its value, check it out in the Immediate Window, or display it somewhere (Console.WriteLine etc.).
Example DataContext.Log usage:
Queries executed on that context will have their SQL statements dumped to the console window. You may copy it from there. To dump them elsewhere, such as to the Debug output window, check out these links:
Step 2: With the SQL statement in hand, use it in ADO.NET
Now that you have the SQL statement we can use it in ADO.NET. Of course you could use a Stored Procedure as well and it shouldn’t be hard to substitute it.
Before using it though, you’ll probably want to clean the statement up. I used a similar query locally to get this and your generated statement probably resembles this:
Notice the embedded SELECT COUNT(*)? The L2S query never requested the count, yet the result requests the count of the equal IDs used on the join. Also notice that there are no aliases for the columns. You would refer to the columns based on their actual names (ie.
post_idversusPostId). In addition, the SQL parameters are named @p0…@pn and a default sort order is applied. You could copy/paste this into the SqlDataReader used earlier, but you would need to rename the columns and parameters to match.A cleaned up version of the above is reproduced below with renamed parameters and unnecessary parts commented out (if this approach is taken test it out to ensure it’s equivalent to what is expected):
The above can now be used with the SqlDataReader from earlier.
A more direct query could’ve been generated if the L2S query was in the format of a SelectMany, such as:
The SelectMany L2S query generates a SQL statement similar to this:
LINQPad
While this detailed explanation might seem overwhelming, there’s an easy way to have this information at your fingertips. If you haven’t given LINQPad a try then I highly recommend it – it’s free too! LINQPad will show you the results of your L2S queries, has a SQL tab to view the generated SQL, and also shows the lambda expression used (the above query syntax is shown as the lambda/extension equivalent). On top of that, it’s a great tool for general purpose C#/VB.NET (including LINQ to Objects/XML), and SQL coding with database support and much more.
Here’s a tiny screenshot of LINQPad showing some of the topics discussed earlier:
I didn’t want to take up more page real estate than I already have so click here to see the image in its original size.
If you made it this far, congrats! 🙂