我是实体框架的新手,并试图学习它可以提供的一切。我目前正在研究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'。可能是一个基本问题,但我会感谢任何正确方向的帮助。
根据要求,这里是我的课程的来源:
Album.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
Genre.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
答案 0 :(得分:2)
只是一个假设的解释:
MusicStore示例使用Entity Framework Code-First开发。它没有任何特殊配置,既没有模型类的代码优先属性,也没有使用流畅的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...
}
现在,由于Genre
类中的Album
属性和Albums
类中的Genre
集合,实体框架知道存在一对多Genre
和Album
之间的关系,它在数据库中映射为外键关系:Albums
表必须具有Genres
表的外键。 EF现在必须弄清楚这个外键的名称是什么,以生成适当的SQL语句。我们的模型没有明确定义外键名称(这也是可能的),因此EF遵循一组惯例,在这种情况下:
Album
类是否具有名为
[目标类的导航属性名称] + [目标类中的主键属性名称]
在我们的例子中,这将是[Genre] + [GenreId] = GenreGenreId
- &gt;不,我们没有这样的财产。
Album
类是否具有名为
[目标类的名称] + [目标类中的主键属性名称]
在我们的例子中,这将是[Genre] + [GenreId] = GenreGenreId
- &gt;不,我们没有这样的财产。
Album
类是否具有名为
[目标类中的主键属性名称]
在我们的案例中,这将是[GenreId] = GenreId
- &gt;是的,我们在Album
。
因此,实体框架将假定Album
类中的外键名称为GenreId
。数据库中与MVCMusicStore示例一起提供的数据库模式确实具有这样的列和外键关系。
因此,我们的查询应该有效。
但是如果我们从public int GenreId { get; set; }
类中删除Album
或写错了(“GenresId”或其他内容)会发生什么?以上三个约定规则都不适用,EF会假设我们的模型类没有表示关系外键的属性。但它仍然假设存在关系(因为导航属性)。要生成涉及此关系的SQL语句,EF必须假定DB中任何外键列的名称。对于此假设,它遵循上述三个规则中的第一个,因此它假定外键名称为GenreGenreId
- 但在数据库模式中,名称为GenreId
- &gt;吊杆!
所以,最后一个问题:您运行的示例的Album
类是否具有GenreId
属性? (我已经看到MusicStore有几个示例步骤,而不是所有这些步骤Album
都有此属性。)
(如果肯定有这样的属性,请忘记这篇文章。)
修改强>:
GenreId
中的{p> Genre
和GenreId
中的Album
必须具有相同的类型,否则上述第三条约定规则不适用。在您的示例中,您有不同的类型(Int16
和Int32
)。这可能是问题所在。
答案 1 :(得分:2)
我有一个类似的问题,似乎是因为Album类有一个GenreID而且Genre类有一个专辑列表。因此EF(我还不明白为什么)现在将开始在为Albums DbSet生成的查询中查找GenreGenreID列。如果为Genre创建一个忽略Genres中的专辑字段的实体配置,那么这将“解决”问题。或者,如果您在Genre上的albums属性中添加ignore属性,它也会“修复”问题。
选项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,但我很确定这是我能够解决这个问题的方法。
答案 2 :(得分:1)
GenreGenreId
应该是GenreId
,这是“相册”实体/相册表和流派实体/流派表中的字段。确保您的数据库设置正确。
答案 3 :(得分:0)
请尝试重新创建模型文件。不应该有任何具有此名称的财产。