我是Linq和EntityFramework的新手。这是我在学习时遇到的示例程序。
表格中的数据如下:
BlogId Title
1 Hello Blog
2 New Blog
3 New Blog
我有以下Linq代码,尝试阅读第一个博客ID(预计为2):
var name = "New Blog";
var blogs = (from b in db.Blogs
where b.Title == name
orderby b.Title
select b);//.ToList();
Console.Write("The first id: ");
Console.WriteLine(blogs.First().BlogId);
结果是3。
然后我使用 ToList():
var blogs = (from b in db.Blogs
where b.Title == name
orderby b.Title
select b).ToList();
Console.Write("The first id: ");
Console.WriteLine(blogs.First().BlogId);
结果是2。
任何人都可以帮忙解释一下吗?或者这是一个错误吗?
感谢。
//////////////////////// 更新 /////////////// //////////////
我刚刚删除了数据库中的数据并插入了一些新项目。现在表格是这样的:
BlogId Title
5 New Blog
6 New Blog
7 New Blog
8 New Blog
然后我运行上面的程序(不带ToList()),First()方法返回id 6 所以我假设该方法总是返回上面情况中的第二项。它似乎与RDBMS没有任何关系。谁能解释一下?
感谢。
/////////////////////////////////////////////// //////
仅供参考,以下是整个.cs文件:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
namespace SampleNew
{
class Program
{
public class Blog
{
[Key]
public Int32 BlogId { get; set; }
public String Title { get; set; }
public virtual List<Post> Posts { get; set; }
}
public class Post
{
[Key]
public Int32 PostId { get; set; }
public String Title{ get; set; }
public String Content { get; set; }
}
public class BlogContext : DbContext
{
public DbSet<Blog> Blogs{ get; set; }
public DbSet<Post> Posts { get; set; }
}
static void Main(string[] args)
{
using (var db = new BlogContext())
{
// Create and save a new Blog
// Console.Write("Enter a name for a new Blog: ");
var name = "New Blog";
//var blog = new Blog { Title = name };
var blogs = (from b in db.Blogs
where b.Title == name
orderby b.Title
select b).ToList();
Console.Write("The first id: ");
Console.WriteLine(blogs.First().BlogId);
Console.WriteLine(blogs.Count());
Blog blog = null;
foreach (Blog b in blogs)
{
blog = b;
Console.WriteLine(blog.BlogId);
}
Console.WriteLine(blog.BlogId);
Console.WriteLine(blogs.First().BlogId);
Console.WriteLine(blogs.First().BlogId);
Console.WriteLine(blogs.Last().BlogId);
Console.WriteLine(blogs.Last().BlogId);
blog.Posts = new List<Post>();
var post = new Post { Content = "Test Content2", Title = "Test Title2"};
blog.Posts.Add(post);
db.Posts.Add(post);
db.SaveChanges();
// Display all Blogs from the database
var query = from b in db.Blogs
orderby b.Title
select b;
Console.WriteLine("All blogs in the database:");
foreach (var item in query)
{
Console.WriteLine(item.Title);
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
}
}
答案 0 :(得分:10)
你有两个相同的头衔,但ID不同。您的RDBMS可以灵活地按照其所希望的顺序返回与'New Blog'
对应的行,因为您的代码没有指定超出标题要求的任何内容。此外,每次运行相同的查询时,甚至不需要以相同的顺序返回结果。
如果您希望获得可预测的结果,请在LINQ语句中添加“then by”以强制执行您希望的排序:
var query = from b in db.Blogs
orderby b.Title, b.BlogId
select b;
编辑:
当我运行上面的程序时,
First()
方法返回id6
,所以我假设该方法总是返回上面情况中的第二项。它似乎与RDBMS没有任何关系。谁能解释一下?
这也发生在RDBMS中,并且在没有LINQ的情况下可以重现。这是一个小型演示(link to sqlfiddle):
create table blogs(blogid int,title varchar(20));
insert into blogs(blogid,title) values (5,'New blog');
insert into blogs(blogid,title) values (6,'New blog');
insert into blogs(blogid,title) values (7,'New blog');
insert into blogs(blogid,title) values (8,'New blog');
SELECT * FROM Blogs ORDER BY Title
此查询以“自然”顺序生成结果:
BLOGID TITLE
------ --------
5 New blog
6 New blog
7 New blog
8 New blog
然而,这个查询,就是EF运行以获取RDBMS中的First()
项目
SELECT TOP 1 * FROM Blogs ORDER BY Title
以自然顺序返回第二个行:
BLOGID TITLE
------ --------
6 New blog
这并不意味着它将在其他RDBMS(link to a demo with MySQL returning a different row for the same query)中返回同一行,甚至不会在同一个RDBMS中返回。它只是演示LINQ依赖于RDBMS来选择行,而RDBMS返回一个任意选择的行。
答案 1 :(得分:0)
我怀疑First()在没有ToList()的情况下进行了优化。
调用ToList()时,必须创建整个有序列表。因此,它将使用有效的排序算法对所有内容进行排序。
然而,使用First(),它只需要找到最小值。因此它可以使用更有效的算法,该算法基本上通过可枚举的一次并存储当前的最小对象值。 (因此它将导致最小值的第一个对象)。
这是一种不同的算法,然后对整个列表进行排序,从而获得不同的结果。
更新: 此外,这是一个数据库,它可能使用linq to sql,它将根据上面的描述生成一个不同的查询(获取一个排序列表vs获得第一个最小值)。