Entity Framework ищет неправильный столбец - PullRequest
1 голос
/ 12 марта 2011

Я новичок в Entity Framework и пытаюсь узнать все, что он может предложить.В настоящее время я работаю над учебником MVC Music Store , который содержит следующий код:

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

Ответы [ 4 ]

2 голосов
/ 20 октября 2012

У меня похожая проблема, и похоже, что у класса Album есть GenreID, а у класса Genre есть список альбомов. Поэтому EF (я пока не понимаю, почему) теперь начнет искать столбец GenreGenreID в запросах, которые он генерирует для DbSet альбомов. Если вы создадите конфигурацию сущности для жанра, которая игнорирует поле альбомов в жанрах, то это «решит» проблему. Или, если вы добавите атрибут игнорирования к свойству album в жанре, это также "исправит" проблему.

Вариант 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 голосов
/ 15 марта 2011

Просто гипотетическое объяснение:

В примере 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 Entity Framework знает, что существует Oneотношение-ко-многим между Genre и Album, которое отображается в базе данных как отношение внешнего ключа: таблица Albums должна иметь внешний ключ к таблице Genres.Теперь EF должен выяснить, как называется этот внешний ключ, чтобы генерировать правильные операторы SQL.Наша модель не определяет имя внешнего ключа явно (что также возможно), поэтому EF следует ряду соглашений, которые в этом случае:

  • Имеет класс Albumиметь свойство с именем

    [имя свойства навигации до целевого класса] + [имя имени свойства первичного ключа в целевом классе]

    В нашем случае это будет [Жанр] + [GenreId] = GenreGenreId -> Нет, у нас такого свойства нет.

  • Имеет ли класс Album свойство с именем

    [nameцелевого класса] + [имя имени свойства первичного ключа в целевом классе]

    Опять в нашем случае это будет [Genre] + [GenreId] = GenreGenreId -> Нет, у нас нет такогосвойство.

  • Имеет ли класс Album свойство с именем

    [имя имени свойства первичного ключа в целевом классе]

    Inв нашем случае это будет [GenreId] = GenreId -> Да, у нас есть такое свойство в Album.

Итак, Entity Framework будетпредположим, что имя внешнего ключа в классе Album равно GenreId.И схема базы данных в БД, которая поставляется с образцом MVCMusicStore, действительно имеет такую ​​связь столбца и внешнего ключа.

Итак, наш запрос должен работать.

Но что произойдет, еслимы удаляем public int GenreId { get; set; } из класса Album или пишем его неправильно ("GenresId" или что-то в этом роде)?Ни одно из трех приведенных выше правил соглашения не будет применяться, и EF предполагает, что у нашего модельного класса нет свойства, представляющего внешний ключ отношения.Но все равно предполагается, что есть связь (из-за свойств навигации).Для генерации операторов SQL, в которых используются эти отношения, EF должен принять любое имя столбца внешнего ключа в БД.И для этого предположения он следует первому из трех приведенных выше правил, поэтому он предполагает, что имя внешнего ключа GenreGenreId - но в схеме базы данных это имя GenreId -> Boom!

Итак, окончательныйвопрос: есть ли у класса Album в примере, который вы запускаете, свойство GenreId?(Я видел, что MusicStore имеет несколько примеров шагов, и не во всех из них Album имеет это свойство.)

(Если оно определенно имеет такое свойство, забудьте этот пост.)

Edit :

GenreId in Genre и GenreId in Album должны иметь один и тот же тип, в противном случае приведенное выше правило третьего соглашения не применяется.В вашем примере у вас есть разные типы (Int16 и Int32).Это может быть проблемой.

1 голос
/ 12 марта 2011

GenreGenreId должно быть GenreId, что является полем в сущности альбома / таблице альбомов и в сущности жанра / таблице жанров.Убедитесь, что ваша база данных настроена правильно.enter image description here

0 голосов
/ 12 марта 2011

Пожалуйста, попробуйте заново создать файл модели. Там не должно быть никаких свойств с этим именем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...