我应该使用Entity Framework导航属性进行查询而不是直接从DataContext ICollections进行查询吗?

时间:2015-03-26 02:08:55

标签: c# entity-framework

我正试图在实体框架6中创建投影并将这些投影映射到我的视图模型。我关心的是使用导航属性时发送的数据库连接数和单独查询数。例如:

(我的根)

var item = db.CourseContainers.First(p => p.ID == id); 
item
   .CourseItems
   .SelectMany(p => p.CourseItemLessons)
   .Select(p => new LessonsListItem() {
      ID = p.CourseItemID,
      Name = p.Lesson.Name
   }).ToList()

我正在使用课程设置拉出所有课程,然后使用课程导航投影到视图模型以获取名称。我不认为我理解实体框架如何解析它。我希望有类似的东西:

SELECT [cil].ID,
       [l].Name
FROM   CourseItems ci INNER JOIN
       CourseItemLessons cil ON ci.ID = cil.CourseItemID INNER JOIN
       Lessons l ON cil.LessonID = l.ID
WHERE  ci.CourseID = @courseID

我刚刚按预期写出来了。我知道表结构有点奇怪。而不是上面,有多个连接和选择语句,这是实际发送到数据库的内容。

SELECT TOP (1) 
    [Extent1].[ID] AS [ID], 
    [Extent1].[ModifiedBy] AS [ModifiedBy], 
    [Extent1].[DateModified] AS [DateModified], 
    [Extent1].[AddedBy] AS [AddedBy], 
    [Extent1].[DateAdded] AS [DateAdded], 
    [Extent1].[Name] AS [Name], 
    [Extent1].[Description] AS [Description], 
    [Extent1].[IsLinear] AS [IsLinear], 
    [Extent1].[Privacy] AS [Privacy]
    FROM [dbo].[CourseContainers] AS [Extent1]
    WHERE [Extent1].[ID] = @p__linq__0


-- p__linq__0: '7' (Type = Int32, IsNullable = false)

-- Executing at 26/03/2015 12:01:44 PM +10:00

-- Completed in 0 ms with result: SqlDataReader



Closed connection at 26/03/2015 12:01:44 PM +10:00

Opened connection at 26/03/2015 12:01:44 PM +10:00

SELECT 
    [Extent1].[ID] AS [ID], 
    [Extent1].[ModifiedBy] AS [ModifiedBy], 
    [Extent1].[DateModified] AS [DateModified], 
    [Extent1].[AddedBy] AS [AddedBy], 
    [Extent1].[DateAdded] AS [DateAdded], 
    [Extent1].[SortOrder] AS [SortOrder], 
    [Extent1].[CourseID] AS [CourseID]
    FROM [dbo].[CourseItems] AS [Extent1]
    WHERE [Extent1].[CourseID] = @EntityKeyValue1


-- EntityKeyValue1: '7' (Type = Int32, IsNullable = false)

-- Executing at 26/03/2015 12:01:44 PM +10:00

-- Completed in 0 ms with result: SqlDataReader



Closed connection at 26/03/2015 12:01:44 PM +10:00

Opened connection at 26/03/2015 12:01:44 PM +10:00

SELECT 
    [Extent1].[ID] AS [ID], 
    [Extent1].[ModifiedBy] AS [ModifiedBy], 
    [Extent1].[DateModified] AS [DateModified], 
    [Extent1].[AddedBy] AS [AddedBy], 
    [Extent1].[DateAdded] AS [DateAdded], 
    [Extent1].[CourseItemID] AS [CourseItemID], 
    [Extent1].[ObjectID] AS [ObjectID]
    FROM [dbo].[CourseItemLessons] AS [Extent1]
    WHERE [Extent1].[CourseItemID] = @EntityKeyValue1


-- EntityKeyValue1: '1049' (Type = Int32, IsNullable = false)

-- Executing at 26/03/2015 12:01:44 PM +10:00

-- Completed in 0 ms with result: SqlDataReader



Closed connection at 26/03/2015 12:01:44 PM +10:00

Opened connection at 26/03/2015 12:01:44 PM +10:00

SELECT 
    [Extent1].[ID] AS [ID], 
    [Extent1].[ModifiedBy] AS [ModifiedBy], 
    [Extent1].[DateModified] AS [DateModified], 
    [Extent1].[AddedBy] AS [AddedBy], 
    [Extent1].[DateAdded] AS [DateAdded], 
    [Extent1].[Name] AS [Name], 
    [Extent1].[Description] AS [Description], 
    [Extent1].[Privacy] AS [Privacy]
    FROM [dbo].[Lessons] AS [Extent1]
    WHERE [Extent1].[ID] = @EntityKeyValue1

这将继续,但有许多课程/课程。

我认为这是因为 item 已经在内存中,但我不确定。如果我将我的代码更改为:

Lessons = (from ci in db.CourseItems
           join cil in db.CourseItemLessons on ci.ID equals cil.CourseItemID
           join l in db.Lessons on cil.ObjectID equals l.ID
           where ci.CourseID == item.ID
           select new { ID = ci.ID, Name = l.Name }).ToList()
           .Select(p => new LessonsListItem() { ID = p.ID, Name = p.Name}).ToList()

我最终得到了预期的结果:

Opened connection at 26/03/2015 12:06:43 PM +10:00

SELECT 
    [Extent1].[ID] AS [ID], 
    [Extent3].[Name] AS [Name]
    FROM   [dbo].[CourseItems] AS [Extent1]
    INNER JOIN [dbo].[CourseItemLessons] AS [Extent2] ON [Extent1].[ID] = [Extent2].[CourseItemID]
    INNER JOIN [dbo].[Lessons] AS [Extent3] ON [Extent2].[ObjectID] = [Extent3].[ID]
    WHERE [Extent1].[CourseID] = @p__linq__0


-- p__linq__0: '7' (Type = Int32, IsNullable = false)

-- Executing at 26/03/2015 12:06:43 PM +10:00

-- Completed in 0 ms with result: SqlDataReader

我知道我可以使用它,但我的意思是,如果要将每一行单独作为具有where子句的select进行查询,使用导航属性会有什么用?

1 个答案:

答案 0 :(得分:0)

问题是First()是投影。如果我拿出First()并将查询添加为where,则IQueryable可以正确解决。

var items = db.CourseContainers
   .Where(p => p.ID == id)
   .SelectMany(p => p.CourseItems)
   .SelectMany(p => p.CourseItemLessons)
   .Select(p => new LessonsListItem() {
      ID = p.CourseItemID,
      Name = p.Lesson.Name
   }).ToList()

以下是有关该问题的更多信息。 Should I use Entity Framework navigation properties for querying rather than straight from the DataContext ICollections?