简体   繁体   中英

Entity framework is trying to use a table that doesn't exist in the SQL for a navigation property

In my C# application (an ASP.NET MVC5 website) I am using Entity Framework 6 as my ORM and I'm using code-first with an existing database. The database is SQL Server 2012 Standard.

In my database I have a view (dbo.vBoardReportLayouts) that functions as a joining table for a number of different elements. I've created an entity for this view and configured the navigation properties.

When I attempt to use this entity with LINQ entity framework generates a SQL query that tries to use a table that doesn't actually exist. Specifically it is looking for the BoardReportLayoutPages table.


Now for all the gory details...

The vBoardReportLayouts view looks like this:

| 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        |

The BoardReportLayouts entity class:

[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; }
}

From the OnModelCreating() method of the dbContext:

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);

The BoardReport, PageType, Page, and PageLayout entities all have the following property defined:

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

Executing this LINQ query:

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

Generates this 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]

The problem is in the FROM clause of the [Join1] table expression. I'm not sure why it is trying to use the table dbo.BoardReportLayoutPages since it could join directly from the view to the Pages table. The table dbo.BoardReportLayoutPages doesn't exist so this throws an exception.

This bit of code is specifying that the BoardReportLayout has a many to many relationship with pages:

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

That means there should be a BoardReportLayoutPages table to model that relationship. The BoardReportLayout is supported by a view, so you had to write the sql to create it yourself, because code first would have generated tables to support the model you have defined here. If you do have a many-to-many relationship here, then you should have created the BoardReportLayoutPages as a table or view also.

But you also have a PageId property in the BoardReportLayout . This means that there is a second one-to-many relationship between a Page and BoardReportLayout s. If you want to get to a BoardReportLayout 's Page via this relationship then you should add a public Page Page { get; set; } public Page Page { get; set; } public Page Page { get; set; } navigation property.

Only you can decide whether you have two relationships here, or just one, and what type of relationship(s) you have.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM