C# 从LINQ查询中获取第一个结果-为什么ElementAt<;T>;(0)当第一次<;T>;()成功了吗?
我有一个方法AddStudent(),它查找同名学生,如果有同名学生,则从数据库返回现有学生,否则它将创建一个新学生并将其添加到数据库中 我很好奇为什么C# 从LINQ查询中获取第一个结果-为什么ElementAt<;T>;(0)当第一次<;T>;()成功了吗?,c#,linq,entity-framework,C#,Linq,Entity Framework,我有一个方法AddStudent(),它查找同名学生,如果有同名学生,则从数据库返回现有学生,否则它将创建一个新学生并将其添加到数据库中 我很好奇为什么se=students.First()成功失败。这两种方法不一样吗 该方法的完整代码如下所示 public Student AddStudent(string name) { using (SchoolEntities db = new SchoolEntities()) { // find student wit
se=students.First()当se=students.ElementAt(0)时,code>成功当我尝试从LINQ查询中获取第一个结果时,代码>失败。这两种方法不一样吗
该方法的完整代码如下所示
public Student AddStudent(string name)
{
using (SchoolEntities db = new SchoolEntities())
{
// find student with same name via LINQ
var students = from s in db.StudentEntitySet
where s.name == name
select s;
StudentEntity se = default(StudentEntity);
// if student with the same name is already present, return
// that student
if (students.Count<StudentEntity>() > 0)
{
// if i use ElementAt, if fails with a "LINQ to Entities does not
// recognize the method 'StudentEntity ElementAt[StudentEntity]
// (System.Linq.IQueryable`1[StudentEntity], Int32)' method,
// and this method cannot be translated into a store expression.",
// but not when I use First. Why?
// se = students.ElementAt<StudentEntity>(0);
se = students.First<StudentEntity>();
}
else
{
// passing 0 for first parameter (id) since it's represented by
// a BigInt IDENTITY field in the database so any value
// doesn't matter.
se = StudentEntity.CreateStudentEntity(0, name);
db.AddToStudentEntitySet(se);
db.SaveChanges();
}
// create a Student object from the Entity object
return new Student(se);
}
}
public Student AddStudent(字符串名)
{
使用(SchoolEntities db=new SchoolEntities())
{
//通过LINQ查找同名学生
var students=来自db.StudentEntitySet中的s
其中s.name==name
选择s;
StudentEntity se=默认值(StudentEntity);
//如果已存在同名学生,请返回
//那个学生
如果(students.Count()>0)
{
//如果我使用ElementAt,如果失败,则使用“LINQ to Entities NOTS”
//在[StudentEntity]中识别方法“StudentEntity元素”
//(System.Linq.IQueryable`1[StudentEntity],Int32)“方法,
//并且此方法无法转换为存储表达式。“,
//但当我第一次使用时就不行了。为什么?
//se=学生。元素AT(0);
se=学生。首先();
}
其他的
{
//正在为第一个参数(id)传递0,因为它由
//数据库中的BigInt标识字段,因此任何值
//没关系。
se=StudentEntity.CreateSudentEntity(0,名称);
db.AddToStudentEntitySet(se);
db.SaveChanges();
}
//从实体对象创建学生对象
返回新生(se);
}
}
谢谢 它失败了,因为ElementAt
方法是一种索引访问方法,实体框架不知道如何将其转换为SQL
使用First
方法时,实体框架可以将其转换为SQL查询中的TOP 1
子句。这很简单。为了使用ElementAt
,它必须基于窗口函数(ROW\u NUMBER()
)构造一个复杂得多的查询,而且它还不够复杂
它实际上是实体框架的一部分。根本不支持ElementAt
扩展
理论上,你可以这样写:
se = students.AsEnumerable().ElementAt<StudentEntity>(0);
se=students.AsEnumerable().ElementAt(0);
这指示实体框架在调用AsEnumerable()
之后不要尝试“翻译”任何内容,因此,它将检索所有结果(而不仅仅是第一个结果)并遍历它们,直到它到达所需的元素(在本例中恰好是第一个)
但是,与仅使用First()
相比,这将大大降低操作的速度,因为它不只是从服务器获取一个结果,而是获取所有结果,然后进行过滤。如果出于某种奇怪的原因,我需要获取第5个或第10个元素或第一个元素以外的其他元素,我只会使用此解决方法。我觉得奇怪的是,它无法执行跳过n TOP 1
@Simon:我不确定您指的是哪个DBMS,但SQL Server没有跳过关键字。实体框架可以使用Skip(n)
和Take(n)
扩展方法进行分页查询(它生成一个行号
查询,如我在回答中所述),但SQL翻译往往是一个接一个地实现的,我猜微软只是没有着手实现ElementAt
,他们认为它不够重要,可能是因为它可以很容易地用Skip(n)
然后Take(1)
组合而成。西蒙:正如阿诺诺所说,你可以通过Skip(n).Take(1).First()来完成。我不确定为什么它不能在内部将ElementAt转换成这个,但我的猜测是,如果结果少于n个,ElementAt就有不同的语义(例如ElementAt应该抛出,但是Skip/Take会导致一个空序列——但第一个仍然会处理抛出…。@Aaronaught:是的,我的意思是ESQL中的SKIP
子句。听起来MSSQL不支持它,但我使用过的大多数其他RDBMs都支持它(语法稍有不同)。比较First()
与Skip(0)生成的SQL。使用(1)。First()
你就会明白为什么首先使用正确的方法更好。:)另一方面,使用var student=db.StudentEntitySet.SingleOrDefault(s=>s.name==name),可以大大简化代码并提高可读性;如果(student!=null){return student;}//Create student hereNice!我会尝试一下。在VS2008中不为EF运行,抛出一个异常“LINQ to Entities不支持方法'Single'。显然适用于EF4-:(无论如何谢谢:)@Neal,使用了FirstOrDefault()而不是SingleOrDefault(),现在可以使用了。代码现在看起来好多了。