【问题标题】:Entity framework is trying to use a table that doesn't exist in the SQL for a navigation property实体框架正在尝试将 SQL 中不存在的表用于导航属性
【发布时间】:2014-11-27 18:18:26
【问题描述】:

在我的 C# 应用程序(一个 ASP.NET MVC5 网站)中,我使用 Entity Framework 6 作为我的 ORM,并且我在现有数据库中使用代码优先。数据库是 SQL Server 2012 Standard。

在我的数据库中,我有一个视图 (dbo.vBoardReportLayouts),它用作许多不同元素的连接表。我为此视图创建了一个实体并配置了导航属性。

当我尝试将此实体与 LINQ 实体框架一起使用时,会生成一个 SQL 查询,该查询会尝试使用一个实际不存在的表。具体来说,它正在寻找BoardReportLayoutPages 表。


现在了解所有血腥的细节......

vBoardReportLayouts 视图如下所示:

| ReportID | PageTypeId | PageId | LayoutID |
+----------+------------+--------+----------+
| 1        | 1          | 1      | 1        |
| 1        | 1          | 1      | 2        |
| 1        | 1          | 2      | 3        |
| 1        | 1          | 3      | 4        |
| 1        | 2          | 4      | 5        |
| 1        | 2          | 4      | 6        |
| 2        | 1          | 1      | 1        |
| 2        | 1          | 1      | 2        |
| 2        | 1          | 2      | 3        |
| 2        | 1          | 3      | 4        |
| 2        | 2          | 4      | 5        |
| 2        | 2          | 4      | 6        |

BoardReportLayouts 实体类:

[Table("vBoardReportLayouts")]
public partial class BoardReportLayout {
    public BoardReportLayout() {
        BoardReports = new HashSet<BoardReport>();
        PageTypes = new HashSet<PageType>();
        Pages = new HashSet<Page>();
        PageLayouts = new HashSet<PageLayout>();
    }

    [Key]
    public int BoardReportLayoutId { get; set; }

    public int BoardReportId { get; set; }

    public int PageTypeId { get; set; }

    public int PageId { get; set; }

    public int PageLayoutId { get; set; }

    public virtual ICollection<BoardReport> BoardReports { get; set; }
    public virtual ICollection<PageType> PageTypes { get; set; }
    public virtual ICollection<Page> Pages { get; set; }
    public virtual ICollection<PageLayout> PageLayouts { get; set; }
}

来自 dbContext 的OnModelCreating() 方法:

modelBuilder.Entity<BoardReportLayout>()
    .HasMany(e => e.BoardReports)
    .WithMany(e => e.BoardReportLayouts);

modelBuilder.Entity<BoardReportLayout>()
    .HasMany(e => e.PageTypes)
    .WithMany(e => e.BoardReportLayouts);

modelBuilder.Entity<BoardReportLayout>()
    .HasMany(e => e.Pages)
    .WithMany(e => e.BoardReportLayouts);

modelBuilder.Entity<BoardReportLayout>()
    .HasMany(e => e.PageLayouts)
    .WithMany(e => e.BoardReportLayouts);

BoardReport、PageType、Page 和 PageLayout 实体都定义了以下属性:

public virtual ICollection<BoardReportLayout> BoardReportLayouts { get; set; }

执行此 LINQ 查询:

var test = (from l in ppdb.BoardReportLayouts
            where l.BoardReportId == 8
            select l.Pages).SelectMany(p => p).ToList();

生成此 SQL:

SELECT [Join1].[PageId] AS [PageId], 
    [Join1].[PageTypeId] AS [PageTypeId], 
    [Join1].[Name] AS [Name], 
    [Join1].[ParameterValue] AS [ParameterValue], 
    [Join1].[SsrsPageParamterValue] AS [SsrsPageParamterValue], 
    [Join1].[TableOfContentsOrder] AS [TableOfContentsOrder]
    FROM  [dbo].[vBoardReportLayouts] AS [Extent1]
    INNER JOIN  (
    SELECT [Extent2].[BoardReportLayout_BoardReportLayoutId] AS [BoardReportLayout_BoardReportLayoutId],
        [Extent3].[PageId] AS [PageId],
        [Extent3].[PageTypeId] AS [PageTypeId],
        [Extent3].[Name] AS [Name],
        [Extent3].[ParameterValue] AS [ParameterValue],
        [Extent3].[SsrsPageParamterValue] AS [SsrsPageParamterValue],
        [Extent3].[TableOfContentsOrder] AS [TableOfContentsOrder]
        FROM  [dbo].[BoardReportLayoutPages] AS [Extent2]
        INNER JOIN [dbo].[Pages] AS [Extent3] ON [Extent3].[PageId] = [Extent2].[Page_PageId]
    ) AS [Join1] ON [Extent1].[BoardReportLayoutId] = [Join1].[BoardReportLayout_BoardReportLayoutId]
    WHERE 8 = [Extent1].[BoardReportId]

问题出在[Join1] 表表达式的FROM 子句中。我不确定它为什么要尝试使用表dbo.BoardReportLayoutPages,因为它可以直接从视图连接到Pages 表。表 dbo.BoardReportLayoutPages 不存在,因此会引发异常。

【问题讨论】:

  • [dbo].[vBoardReportLayouts] 来自哪里? (注意 v)。
  • vBoardReportLayouts 是我在数据库中创建的视图。 Pages 和 PageLayouts 表中的行都有日期(开始和结束日期),日期指定它们适用于哪些 BoardReports。 BoardReport 实际上是一个月,但在 BoardReport 表中存储了该月的其他属性。我决定使用视图来处理表的连接逻辑,以便我仍然可以在 EF 中使用本机导航属性,但看起来这不会像我希望的那样工作。

标签: c# linq entity-framework entity-framework-6


【解决方案1】:

这段代码指定BoardReportLayout 与页面具有多对多 关系:

modelBuilder.Entity<BoardReportLayout>()
    .HasMany(e => e.Pages)
    .WithMany(e => e.BoardReportLayouts);

这意味着应该有一个BoardReportLayoutPages 表来模拟这种关系。 BoardReportLayout 由视图支持,因此您必须自己编写 sql 来创建它,因为代码首先会生成表以支持您在此处定义的模型。如果您在这里确实有一个多对多关系,那么您应该也将BoardReportLayoutPages 创建为一个表或视图。

但您在BoardReportLayout 中还有一个PageId 属性。这意味着PageBoardReportLayouts 之间存在第二个一对多 关系。如果您想通过这种关系访问BoardReportLayoutPage,那么您应该添加一个public Page Page { get; set; } 导航属性。

只有你自己可以决定你是有两种关系,还是只有一种,以及你有什么类型的关系。

【讨论】:

    猜你喜欢
    • 2012-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-01
    • 2016-04-22
    相关资源
    最近更新 更多