数据库
首页 > 数据库> > 我如何将此linq代码转换为嵌入式SQL

我如何将此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