IQueryable 未在 entity framework 核心中生成所需的查询
IQueryable not generating the desired query in entity framework core
我有一些类似于以下的实体:
public class Teacher
{
public int TeacherId { get; set; }
public string TeacherName { get; set; }
public int Age { get; set; }
public string CurrentGrade { get; set; }
public int YearsTeaching { get; set; }
pubilc ICollection<StudentFeedback> StudentFeedback { get; set; }
}
public class StudentFeedback
{
public int StudentFeedBackId { get; set; }
public int TeacherId { get; set; }
public int StudentId { get; set; }
public string Feedback { get; set; }
public Teacher Teacher { get; set; }
public Student Student { get; set; }
}
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
public int Age { get; set; }
public string CurrentGrade { get; set; }
}
我有一个存储库,其中包含我想要 return 一位教师或教师列表,其中 StudentFeedback returned 属于正在查看它的学生(studentId 存储在令牌中)。
所以,假设我有教师 (teacherId) 和学生 (userId),他们正在点击 API 端点。我目前有以下内容:
int teacherId = 2;
int userId = 20; // This is the currently logged in user, extracted from the token.
var query = _context.Teachers.AsQueryable();/* _context is the DataContext*/
query = query.Where(t => p.TeacherId == teacherId);
query = query.Where(u => u.StudentFeedback.Any(x => x.StudentId == userId));
然而,这仍然是 return 所有学生的所有 StudentFeedback,只要 userId(学生)为相关教师提供了反馈。我查看了执行的查询,问题是 studentId 谓词在错误的位置。一个非常粗略的查询版本是:
SELECT *
FROM ( SELECT t.*
FROM dbo.Teachers t
WHERE (t.TeacherId = 2)
AND EXISTS ( SELECT 1
FROM dbo.StudentFeedback t0
WHERE (t.TeacherId = t0.TeacherId)
AND (t0.StudentId = 20))) p
LEFT JOIN dbo.StudentFeedback sf ON p.TeacherId = sf.TeacherId
而它应该是这样的
SELECT *
FROM ( SELECT t.*
FROM dbo.Teachers t
WHERE (t.TeacherId = 2)) p
LEFT JOIN dbo.StudentFeedback sf ON p.TeacherId = sf.TeacherId
AND sf.StudentId = 20
但我不知道如何实现。我设置的 IQueryable 谓词有问题还是我错过了数据上下文中 modelBuilder 中的某些逻辑?
谢谢。
编辑:我正在使用 Entity Framework Core 5.0.2,我也在使用带有以下代码的 Automapper:
query.ProjectTo<TeacherDTO>(_mapper.ConfigurationProvider).AsNoTracking()
这是我目前得到的:
[
{
"teacherid": 2,
"teacherName": "Jane Smith",
"age": 35,
"currentGrade": "One",
"yearsTeaching": 12,
"studentFeedback": [
{
"studentFeedBackId": 12,
"teacherId": 6,
"studentId": 20,
"feedback": "Ms Smith is my favorite teacher"
} ,
{
"studentFeedBackId": 16,
"teacherId": 6,
"studentId": 43,
"feedback": "Ms Smith was so kind to me"
} ,
{
"studentFeedBackId": 21,
"teacherId": 6,
"studentId": 89,
"feedback": "Thank you Mrs Smith for being my teacher. I learned a lot."
}
]
}
]
这是我想要得到的:
[
{
"teacherid": 2,
"teacherName": "Jane Smith",
"age": 35,
"currentGrade": "One",
"yearsTeaching": 12,
"studentFeedback": [
{
"studentFeedBackId": 12,
"teacherId": 6,
"studentId": 20,
"feedback": "Ms Smith is my favorite teacher"
}
]
}
]
如果你想要一个连接,你应该在你的 linq 语句中使用 Join 方法。参见 https://www.tutorialsteacher.com/linq/linq-joining-operator-join。您得到的正是您在查询中所写的内容。 Where(u => u.StudentFeedback.Any(x => x.StudentId == userId));
.Any 转换为存在。
如果您使用 Net5 EF,您只需将学生 属性 添加到教师 class:
public class Teacher
{
.....
pubilc ICollection<Student> Students { get; set; }
pubilc ICollection<StudentFeedback> StudentFeedbacks { get; set; }
}
您可以这样使用查询:
var query = _context.Teachers.Include(i=> i.StudentFeedbacks)
.Where(t =>
t.TeacherId == teacherId
&& t.StudentFeedbacks.Any(x => x.StudentId == userId))
.ToArray();
感谢@LucianBargaoanu 通过在映射本身中包含 where
来为我指明正确的方向。解决方法是在使用Automapper时使用Parameterization:
此页面中的代码显示了一个示例:
string currentUserName = null;
cfg.CreateMap<Course, CourseModel>()
.ForMember(m => m.CurrentUserName, opt => opt.MapFrom(src => currentUserName));
然后
dbContext.Courses.ProjectTo<CourseModel>(Config, new { currentUserName = Request.User.Name });
我有一些类似于以下的实体:
public class Teacher
{
public int TeacherId { get; set; }
public string TeacherName { get; set; }
public int Age { get; set; }
public string CurrentGrade { get; set; }
public int YearsTeaching { get; set; }
pubilc ICollection<StudentFeedback> StudentFeedback { get; set; }
}
public class StudentFeedback
{
public int StudentFeedBackId { get; set; }
public int TeacherId { get; set; }
public int StudentId { get; set; }
public string Feedback { get; set; }
public Teacher Teacher { get; set; }
public Student Student { get; set; }
}
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
public int Age { get; set; }
public string CurrentGrade { get; set; }
}
我有一个存储库,其中包含我想要 return 一位教师或教师列表,其中 StudentFeedback returned 属于正在查看它的学生(studentId 存储在令牌中)。
所以,假设我有教师 (teacherId) 和学生 (userId),他们正在点击 API 端点。我目前有以下内容:
int teacherId = 2;
int userId = 20; // This is the currently logged in user, extracted from the token.
var query = _context.Teachers.AsQueryable();/* _context is the DataContext*/
query = query.Where(t => p.TeacherId == teacherId);
query = query.Where(u => u.StudentFeedback.Any(x => x.StudentId == userId));
然而,这仍然是 return 所有学生的所有 StudentFeedback,只要 userId(学生)为相关教师提供了反馈。我查看了执行的查询,问题是 studentId 谓词在错误的位置。一个非常粗略的查询版本是:
SELECT *
FROM ( SELECT t.*
FROM dbo.Teachers t
WHERE (t.TeacherId = 2)
AND EXISTS ( SELECT 1
FROM dbo.StudentFeedback t0
WHERE (t.TeacherId = t0.TeacherId)
AND (t0.StudentId = 20))) p
LEFT JOIN dbo.StudentFeedback sf ON p.TeacherId = sf.TeacherId
而它应该是这样的
SELECT *
FROM ( SELECT t.*
FROM dbo.Teachers t
WHERE (t.TeacherId = 2)) p
LEFT JOIN dbo.StudentFeedback sf ON p.TeacherId = sf.TeacherId
AND sf.StudentId = 20
但我不知道如何实现。我设置的 IQueryable 谓词有问题还是我错过了数据上下文中 modelBuilder 中的某些逻辑? 谢谢。
编辑:我正在使用 Entity Framework Core 5.0.2,我也在使用带有以下代码的 Automapper:
query.ProjectTo<TeacherDTO>(_mapper.ConfigurationProvider).AsNoTracking()
这是我目前得到的:
[
{
"teacherid": 2,
"teacherName": "Jane Smith",
"age": 35,
"currentGrade": "One",
"yearsTeaching": 12,
"studentFeedback": [
{
"studentFeedBackId": 12,
"teacherId": 6,
"studentId": 20,
"feedback": "Ms Smith is my favorite teacher"
} ,
{
"studentFeedBackId": 16,
"teacherId": 6,
"studentId": 43,
"feedback": "Ms Smith was so kind to me"
} ,
{
"studentFeedBackId": 21,
"teacherId": 6,
"studentId": 89,
"feedback": "Thank you Mrs Smith for being my teacher. I learned a lot."
}
]
}
]
这是我想要得到的:
[
{
"teacherid": 2,
"teacherName": "Jane Smith",
"age": 35,
"currentGrade": "One",
"yearsTeaching": 12,
"studentFeedback": [
{
"studentFeedBackId": 12,
"teacherId": 6,
"studentId": 20,
"feedback": "Ms Smith is my favorite teacher"
}
]
}
]
如果你想要一个连接,你应该在你的 linq 语句中使用 Join 方法。参见 https://www.tutorialsteacher.com/linq/linq-joining-operator-join。您得到的正是您在查询中所写的内容。 Where(u => u.StudentFeedback.Any(x => x.StudentId == userId));
.Any 转换为存在。
如果您使用 Net5 EF,您只需将学生 属性 添加到教师 class:
public class Teacher
{
.....
pubilc ICollection<Student> Students { get; set; }
pubilc ICollection<StudentFeedback> StudentFeedbacks { get; set; }
}
您可以这样使用查询:
var query = _context.Teachers.Include(i=> i.StudentFeedbacks)
.Where(t =>
t.TeacherId == teacherId
&& t.StudentFeedbacks.Any(x => x.StudentId == userId))
.ToArray();
感谢@LucianBargaoanu 通过在映射本身中包含 where
来为我指明正确的方向。解决方法是在使用Automapper时使用Parameterization:
此页面中的代码显示了一个示例:
string currentUserName = null;
cfg.CreateMap<Course, CourseModel>()
.ForMember(m => m.CurrentUserName, opt => opt.MapFrom(src => currentUserName));
然后
dbContext.Courses.ProjectTo<CourseModel>(Config, new { currentUserName = Request.User.Name });