我如何将此linq代码转换为嵌入式SQL
作者:互联网
我将如何隐瞒此查询以内联sql或存储过程?
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);
}
内联查询执行后,如何将信息放入自定义类中? PostComments是一个子查询-那么我将如何使用ADO.NET将其放在自定义类中?
解决方法:
简短说明
您的问题中似乎有些棘手的部分是如何以与LINQ to SQL(此后称为“ L2S”)查询匿名类相同的方式填充自定义类.
根据您的foreach循环,我猜您的自定义类与以下类似:
public class PostType
{
public int PostId { get; set; }
public List<PostComment> PostComments { get; set; }
}
public class PostComment
{
public int CommentId { get; set; }
public string Title { get; set; }
}
LINQ查询应等效于以下T-SQL语句:
SELECT P.post_id, C.id, C.title
FROM post As P, comment As C
WHERE
P.post_id = @PostId
AND P.post_isdeleted = 0 -- 0 is false
AND C.CommentPostID = P.post_id
与L2S版本不同(有关更多信息,请参见下面的“详细说明”部分),此语句返回平化的结果,每行包含P.post_id,C.id和C.title.如果您的PostType类以相同的方式表示一个条目,则将很容易解决(我不主张这种设计;我只是在评论设计如何更改其填充方式).类中的层次关系改变了事情.
此外,您的代码还显示了List< PostType>但是列表不是必需的,因为由于您要过滤post_id,因此始终会有一个PostType.如果删除了该条件,则在满足其他条件的情况下,您可能会获得具有不同PostId的多个匹配项.如果是这种情况,下面的代码将需要更改.
也就是说,让我们跳入ADO.NET并使用SqlDataReader填充类.
int postIdInput = 42; // desired post_id to search for
// PostType delcared prior to getting the results
PostType postType = new PostType()
{
PostId = postIdInput,
PostComments = new List<PostComment>()
};
// Database interaction starts here...
// updated SQL statement to use column name aliases for clarity when used by the SqlDataReader
string sqlStatement = @"SELECT P.post_id As PostId, C.id As CommentId, C.title As Title
FROM post As P, comment As C
WHERE
P.post_id = @PostId
AND P.post_isdeleted = 0 -- 0 is false
AND C.CommentPostID = P.post_id";
string sqlConnectionString = "..."; // whatever your connection is... probably identical to your L2S context.Connection.ConnectionString
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
{
conn.Open();
SqlCommand command = new SqlCommand(sqlStatement, conn);
command.Parameters.AddWithValue("@PostId", postIdInput); // use Parameters.Add() for greater specificity
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
// postId was set based on input, but could be set here as well although it would occur repeatedly
// if desired, uncomment the 2 lines below and there's no need to initialize it earlier (it'll be overwritten anyway)
//int postId = Int32.Parse(reader["PostId"].ToString());
//postType.PostId = postId;
int commentId = Int32.Parse(reader["CommentId"].ToString());
string title = reader["Title"].ToString();
// add new PostComment to the list
PostComment postComment = new PostComment
{
CommentId = commentId,
Title = title
};
postType.PostComments.Add(postComment);
}
// done! postType is populated...
}
// use postType...
那应该涵盖您的情况.但是,要获得更详细的答案,请继续阅读!
详细说明(又名“教人钓鱼…”)
假设您不知道如何获取等效的SQL语句.尽管有不同的方法可以做到这一点,但我将重点介绍您正在使用L2S的事实,并探讨一些相关的选项.
步骤1:将LINQ查询转换为SQL(通过“作弊”)
您很幸运,因为这里有捷径.与将SQL转换为LINQ相比,将现有的LINQ表达式转换为SQL稍微容易一些.
您可以使用以下两个DataContext选项之一从代码中获取翻译后的T-SQL语句:
> DataContext.GetCommand() method
> DataContext.Log property
注意:我确实说这是捷径.了解SQL是很不错的知识,并且要明确地说,我不建议盲目使用生成的输出.当然,SQL有时可能与您期望的有所不同,但是它提供了一个不错的起点.您可以根据需要进行调整.
使用这两种方法之一并复制结果-步骤2将需要它.
示例DataContext.GetCommand()用法:
var query = /* your L2S query here */;
string sqlStatement = context.GetCommand(query).CommandText; // voila!
要获得结果,请设置一个断点并复制其值,在“即时窗口”中将其检出,或将其显示在某个位置(Console.WriteLine等).
示例DataContext.Log用法:
context.Log = Console.Out;
在该上下文中执行的查询会将其SQL语句转储到控制台窗口.您可以从那里复制它.要将它们转储到其他位置,例如到“调试输出”窗口,请查看以下链接:
> Damien Guard的博客文章:LINQ to SQL log to debug window, file, memory or multiple writers
> Sending the LINQ To SQL log to the debugger output window
步骤2:掌握SQL语句,然后在ADO.NET中使用它
现在您有了SQL语句,我们可以在ADO.NET中使用它了.当然,您也可以使用存储过程,并且用它代替它并不难.
在使用它之前,您可能需要清除该语句.我在本地使用了类似的查询来获取此信息,并且您生成的语句可能类似于以下内容:
SELECT [t0].[post_id], [t1].[id], [t1].[title], (
SELECT COUNT(*)
FROM [comment] AS [t2]
WHERE [t2].[id] = [t0].[post_id]
) As [value]
FROM [post] As [t0]
LEFT OUTER JOIN [comment] As [t1] ON [t1].[CommentPostID] = [t0].[post_id]
WHERE ([t0].[post_id] = @p0) AND ([t0].[post_isdeleted] = 0)
ORDER BY [t0].[post_id], [t1].[id]
注意嵌入式的SELECT COUNT(*)吗? L2S查询从不请求计数,但是结果请求联接中使用的相等ID的计数.另请注意,这些列没有别名.您将根据其实际名称(即post_id与PostId)来参考这些列.此外,SQL参数被命名为@ p0 … @ pn并应用默认的排序顺序.您可以将其复制/粘贴到先前使用的SqlDataReader中,但是您需要重命名列和参数以进行匹配.
下面是上述内容的清理版本,其中重命名了参数,并注释掉了不必要的部分(如果采用此方法,请对其进行测试,以确保它与预期的效果相同):
SELECT [P].[post_id] As PostId, [C].[id] As CommentId, [C].[title] As Title--, (
-- SELECT COUNT(*)
-- FROM [comment] AS [t2]
-- WHERE [t2].[id] = [t0].[post_id]
-- ) As [value]
FROM [post] As [P]
LEFT OUTER JOIN [comment] As [C] ON [C].[CommentPostID] = [P].[post_id]
WHERE ([P].[post_id] = @PostId) AND ([P].[post_isdeleted] = 0)
--ORDER BY [t0].[post_id], [t1].[id]
上面的内容现在可以与SqlDataReader一起使用.
如果L2S查询的格式为SelectMany,则可能会生成更直接的查询,例如:
var query = from arow in context.post
from c in context.comment
where arow.post_id == id && arow.post_isdeleted == false
&& c.CommentPostID == arow.post_id
select new
{
arow.post_id,
c.id,
c.title
};
SelectMany L2S查询生成类似于以下内容的SQL语句:
SELECT [t0].[post_id], [t1].[id], [t1].[title]
FROM [post] As [t0], [comment] As [t1]
WHERE ([t0].[post_id] = @p0) AND ([t0].[post_isdeleted] = 0)
AND ([t1].[CommentPostID] = [t0].[post_id])
LINQPad
尽管这种详尽的解释似乎不胜枚举,但有一种简便的方法可让您唾手可得.如果您没有尝试LINQPad,那么我强烈推荐您-它也是免费的! LINQPad将向您显示L2S查询的结果,具有一个SQL选项卡以查看生成的SQL,还显示所使用的lambda表达式(上述查询语法显示为lambda / extension等效项).最重要的是,它是用于通用C#/ VB.NET(包括LINQ to Objects / XML)以及具有数据库支持等功能的SQL编码的出色工具.
这是LINQPad的小屏幕截图,显示了前面讨论的一些主题:
click here to see the image in its original size我不想占用比现在更多的页面空间.
如果您做到了这一点,恭喜!
标签:ado-net,linq-to-entities,linq,c 来源: https://codeday.me/bug/20191210/2100932.html