【问题标题】:Entity Framework looking for wrong column实体框架寻找错误的列
【发布时间】:2011-03-12 18:36:49
【问题描述】:

我是 Entity Framework 的新手,我正在努力学习它所能提供的一切。我目前正在通过MVC Music Store tutorial 工作,其中包括以下代码:

public ActionResult Browse(string genre)
 {
    // Retrieve Genre and its Associated Albums from database
    var genreModel = storeDB.Genres.Include("Albums")
        .Single(g => g.Name == genre);

    return View(genreModel);
 }

当我在 VB 中工作时,我将其转换为:

Function Browse(ByVal genre As String) As ActionResult

            'Retrieve Genre and its Associated Albums from database
            Dim genreModel = storeDB.Genres.Include("Albums"). _
                    Single(Function(g) g.Name = genre)

            Return(View(genreModel))
        End Function

问题是我遇到了以下异常:

无效的列名“GenreGenreId”。

我知道这是真的,但我无法在我的作品中找到“GenreGenreId”的来源。可能是一个基本问题,但我将不胜感激在正确方向上的任何帮助。


根据要求,这里是我的课程的来源:

专辑.vb

Public Class Album

    Private _title As String
    Private _genre As Genre
    Private _AlbumId As Int32
    Private _GenreId As Int32
    Private _ArtistId As Int32
    Private _Price As Decimal
    Private _AlbumArtUrl As String

    Public Property Title As String
        Get
            Return _title
        End Get
        Set(ByVal value As String)
            _title = value
        End Set
    End Property

    Public Property AlbumId As Int16
        Get
            Return _AlbumId
        End Get
        Set(ByVal value As Int16)
            _AlbumId = value
        End Set
    End Property

    Public Property GenreId As Int16
        Get
            Return _GenreId
        End Get
        Set(ByVal value As Int16)
            _GenreId = value
        End Set
    End Property

    Public Property ArtistId As Int16
        Get
            Return _ArtistId
        End Get
        Set(ByVal value As Int16)
            _ArtistId = value
        End Set
    End Property

    Public Property AlbumArtUrl As String
        Get
            Return _AlbumArtUrl
        End Get
        Set(ByVal value As String)
            _AlbumArtUrl = value
        End Set
    End Property

    Public Property Price As Decimal
        Get
            Return _Price
        End Get
        Set(ByVal value As Decimal)
            _Price = value
        End Set
    End Property

    Public Property Genre As Genre
        Get
            Return _genre
        End Get
        Set(ByVal value As Genre)
            _genre = value
        End Set
    End Property


End Class

流派.vb

Public Class Genre

    Dim _genreId As Int32
    Dim _Name As String
    Dim _Description As String
    Dim _Albums As List(Of Album)

    Public Property GenreId As Int32
        Get
            Return _genreId
        End Get
        Set(ByVal value As Int32)
            _genreId = value
        End Set
    End Property

    Public Property Name As String
        Get
            Return _Name
        End Get
        Set(ByVal value As String)
            _Name = value
        End Set
    End Property

    Public Property Description As String
        Get
            Return _Description
        End Get
        Set(ByVal value As String)
            _Description = value
        End Set
    End Property

    Public Property Albums As List(Of Album)
        Get
            Return _Albums
        End Get
        Set(ByVal value As List(Of Album))
            _Albums = value
        End Set
    End Property

End Class

MusicStoreEntities.vb

Imports System.Data.Entity

Namespace MvcApplication1

    Public Class MusicStoreEntities
        Inherits DbContext

        Public Property Albums As DbSet(Of Album)
        Public Property Genres As DbSet(Of Genre)

    End Class
End Namespace

【问题讨论】:

    标签: c# asp.net asp.net-mvc vb.net entity-framework


    【解决方案1】:

    只是一个假设的解释:

    MusicStore 示例使用实体框架代码优先开发。而且它没有任何特殊配置,既没有模型类的代码优先属性,也没有使用 fluent API。

    这意味着 EntityFramework 完全从一组在幕后定义并基于模型类的类和属性名称的约定推断数据库结构和所有关系。

    失败查询的重要类是(简化的,只有相关的属性):

    public class Genre
    {
        public int GenreId { get; set; }
        public string Name { get; set; }
        public List<Album> Albums { get; set; }
    }
    
    public class Album
    {
        public int AlbumId { get; set; }
        public int GenreId { get; set; }
        public virtual Genre Genre { get; set; }
    }
    

    而 DbContext 是:

    public class MusicStoreEntities : DbContext
    {
        public DbSet<Album> Albums { get; set; }
        public DbSet<Genre> Genres { get; set; }
        // other sets...         
    }
    

    现在,由于Album 类中的Genre 属性和Genre 类中的Albums 集合,实体框架知道Genre 和@987654328 之间存在一对多关系在数据库中映射为外键关系的@:Albums 表必须具有Genres 表的外键。 EF 现在必须弄清楚这个外键的名称是什么,才能生成正确的 SQL 语句。我们的模型没有明确定义外键名称(这也是可能的),因此 EF 遵循一组在这种情况下的约定:

    • Album 类是否有一个名为

      [目标类的导航属性名称]+[目标类中的主键属性名称]

      在我们的例子中,这将是 [Genre]+[GenreId] = GenreGenreId -> 不,我们没有这样的属性。

    • Album 类是否有一个名为

      [目标类名]+[目标类主键属性名]

      在我们的例子中,这将是 [Genre]+[GenreId] = GenreGenreId -> 不,我们没有这样的属性。

    • Album 类是否有一个名为

      [目标类中的主键属性名]

      在我们的例子中,这将是 [GenreId] = GenreId -> 是的,我们在 Album 中有这样一个属性。

    因此,Entity Framework 将假定Album 类中的外键名称为GenreId。而MVCMusicStore示例提供的DB中的数据库模式确实有这样的列和外键关系。

    所以,我们的查询应该可以工作了。

    但是,如果我们从 Album 类中删除 public int GenreId { get; set; } 或写错(“GenresId”或其他东西)会发生什么?上述三个约定规则都不适用,EF 会假设我们的模型类没有表示关系外键的属性。但它仍然假设存在关系(因为导航属性)。要生成涉及这种关系的 SQL 语句,EF 必须假定数据库中外键列的任何名称。对于这个假设,它遵循上述三个规则中的第一个,因此它假设外键名称是 GenreGenreId - 但在数据库模式中,名称是 GenreId -> Boom!

    那么,最后一个问题:您正在运行的示例的Album 类是否具有GenreId 属性? (我看到 MusicStore 有几个示例步骤,并不是所有的Album 都有这个属性。)

    (如果它确实有这样的属性,请忘记这篇文章。)

    编辑

    Genre 中的GenreIdAlbum 中的GenreId 必须具有相同的类型,否则上面的第三个约定规则不适用。在您的示例中,您有不同的类型(Int16Int32)。这可能是问题所在。

    【讨论】:

    • 感谢这篇出色的帖子,您让我注意到我的 Album 类中的一些不正确的属性。我现在已经修复了它们,但是......仍然是同样的问题。您还有其他想法吗?
    • @m.edmondson:不,遗憾的是目前没有其他想法。但是,如果您可以在问题中编辑一些附加信息,这将有所帮助:1)Album 类,2)Genre 类,3)派生的 DbContext 类。问题一定出在这个区域的某个地方。
    • 我已按要求编辑了问题 - 非常感谢您的帮助
    • @m.edmondson:请参阅我的回答中的编辑。也许就是这样。
    • 最好将Int16改为Int32,因为数据库中的列类型是int,它是一个32位整数。
    【解决方案2】:

    我有一个类似的问题,这似乎是因为 Album 类有一个 GenreID,而 Genre 类有一个专辑列表。所以 EF(我还不明白为什么)现在将开始在它为 Albums DbSet 生成的查询中寻找 GenreGenreID 列。如果您为流派创建一个忽略流派中的专辑字段的实体配置,那么这将“解决”问题。或者,如果您将忽略属性添加到 Genre 的专辑属性,它也会“修复”问题。

    选项 1:

        public class GenreConfiguration : EntityTypeConfiguration<Genre>
        {
            public GenreConfiguration()
                : base()
            {
                HasKey(p => p.GenreId);
                Property(p => p.GenreId).
                    HasColumnName("GenreId").
                    HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).
                    IsRequired();
                Property(p => p.Name).
                    HasColumnName("Name").
                    IsRequired();
                Ignore(p => p.Albums);
            }
        }
    

    在 OnModelCreating 方法中,您的 dbcontext 您将需要类似的内容

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
           modelBuilder.Configurations.Add<Genre>(new GenreConfiguration());
           modelBuilder.Entity<Genre>().ToTable("Genre");
        }
    

    选项 2:

        public class Genre
        {
            public int GenreId { get; set; }
            public string Name { get; set; }
    
            [NotMapped]
            public List<Album> Albums { get; set; }
        }
    

    您现在的问题是您必须自己填充流派的专辑字段。我自己并不精通 EF,但我很确定这就是我能够解决这个问题的方法。

    【讨论】:

      【解决方案3】:

      GenreGenreId 应该是GenreId,这是专辑实体/专辑表和流派实体/流派表中的一个字段。确保您的数据库设置正确。

      【讨论】:

      • 我明白这一点,我使用了下载中提供的确切数据库。我的问题是它为什么还要寻找 GenreGenreId?
      【解决方案4】:

      请尝试重新创建模型文件。不应有任何具有此名称的属性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-05
        • 2015-06-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多