简短说明
加载它在列表看来部分你的问题可能看起来比较棘手,那就是如何以与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
。如果你的类以相同的方式代表一个入口,这将很容易解决(我不主张这样的设计;我只是在评论设计如何改变它如何填充)。类中的层次关系改变了事物。
此外,您的代码显示List<PostType>
,但不需要列表,因为总是会有一个PostType
,因为您在post_id
上进行筛选。如果该条件被删除,则,然后您可能会在满足其他条件的情况下获得与具有不同PostIds的多个匹配项。如果是这种情况,下面的代码将需要更改。
也就是说,让我们跳入一些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 (通过 “欺骗”)
你很幸运,因为有一个快捷方式。将现有的LINQ表达式转换为SQL比向后翻译SQL和LINQ更方便。
您可以通过使用这些DataContext的选项从您的代码转换的T-SQL语句:
注:我没有说这是一条捷径。 SQL的知识很好理解,并且要清楚我并不是建议盲目使用生成的输出。当然,SQL可能与您期望的有所不同,但它提供了一个体面的起点。如果需要,你可以调整它。
使用这些方法中的任何一种并复制结果 - 您将需要它的步骤2。
实施例DataContext.GetCommand()的用法:
var query = /* your L2S query here */;
string sqlStatement = context.GetCommand(query).CommandText; // voila!
要获得的结果要么设置断点和复制其值,检查出来在立即窗口,或某处显示它(Console.WriteLine等等。)。
例DataContext.Log用法:在这种情况下执行将转储到控制台窗口的SQL语句
context.Log = Console.Out;
查询。你可以从那里复制它。在其他地方把它们扔掉,比如到调试输出窗口,请查看以下链接:
第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
};
的L2S的SelectMany查询生成类似下面的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。
如果您到此为止,恭喜!:)
你正在使用什么SQL?如果你使用t-sql,答案将不会像你使用plsql一样。 – ALOToverflow 2010-01-20 17:31:07
我正在使用sql server – Luke101 2010-01-20 17:48:17