我是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”。可能是一个基本问题,但是如果您对正确的方向有所帮助,我将不胜感激。
根据要求,这里是我的课程的来源:
相册
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
流派
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
最佳答案
只是一个假设的解释:
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
->不,我们没有这样的属性。Album
类是否具有一个名为的属性[目标类别的名称] + [目标类别中的主键属性名称的名称]
同样在我们的情况下,这将是[Genre] + [GenreId] =
GenreGenreId
->不,我们没有这样的属性。Album
类是否具有一个名为的属性[目标类中的主键属性名称的名称]
在我们的情况下,这将是[GenreId] =
GenreId
->是的,我们在Album
中具有这样的属性。因此,实体框架将假定
Album
类中的外键名称为GenreId
。 MVCMusicStore示例随附的数据库中的数据库架构确实具有这样的列和外键关系。因此,我们的查询应该工作。
但是,如果我们从
public int GenreId { get; set; }
类中删除Album
或将其写错(“ GenresId”等),会发生什么?上面的三个约定规则都不适用,EF假定我们的模型类没有代表关系外键的属性。但是它仍然假定存在关系(由于导航属性)。要生成涉及此关系的SQL语句,EF必须采用数据库中外键列的任何名称。对于此假设,它遵循上述三个规则中的第一个,因此假定外键名称为GenreGenreId
-但在数据库模式中,名称为GenreId
-> Boom!因此,最后一个问题:您正在运行的示例的
Album
类是否具有GenreId
属性? (我已经看到,MusicStore有几个示例步骤,而并非所有Album
都具有此属性。)(如果它绝对具有这样的属性,请忽略此帖子。)
编辑:
GenreId
中的Genre
和GenreId
中的Album
必须具有相同的类型,否则上面的第三条约定规则将不适用。在您的示例中,您有不同的类型(Int16
和Int32
)。这可能是问题所在。