Entity Framework Code First TPC Inheritance Самостоятельная ссылка на дочерний класс - PullRequest
2 голосов
/ 09 января 2012

У меня проблема с Entity Framework и наследованием TPC с самообращающимся дочерним классом.

Определения моего класса:

Public Class BaseObject
    <Key()>
    <DatabaseGenerated(DatabaseGeneratedOption.None)>
    Public Overridable Property iId As Integer

    <Required()>
    Public Property iModUserId As Integer

    <ForeignKey("iModUserId")>
    Public Property ModUser As User

    <Required()>
    Public Property dtModDate As DateTime
End Class

Public Class User
    Inherits BaseObject

    <Required()>
    Public Property sFirstName As String

    <Required()>
    Public Property sLastName As String
End Class

Это мой контекст

Public Class DBTestContext
    Inherits DbContext

    Public Property BaseObjects As DbSet(Of BaseObject)

    Protected Overrides Sub OnModelCreating(modelBuilder As System.Data.Entity.DbModelBuilder)
        modelBuilder.Entity(Of User)().Map(Sub(m)
                                               m.MapInheritedProperties()
                                               m.ToTable("tUsers")
                                           End Sub)
    End Sub

End Class

Проблема заключается в том, что Entity Framework устанавливает отношение внешнего ключа (FK) к таблице, созданной для «BaseClass», а НЕ к таблице, созданной для класса «User».

Это серьезная проблема, поскольку в таблицу «BaseClass» не должно быть вставлено ничего, и поэтому ограничение внешнего ключа нарушается при вставке нового пользователя:

Dim context As DBTestContext = New DBTestContext()

Dim user1 As User = New User()

user1.iId = 1
user1.iModUserId = 1
user1.dtModDate = DateTime.Now

context.Users.Add(user1)
context.SaveChanges() 'Error occurs here.

Код работает отлично, если я удалю наследство. Код также работает, если я удаляю DBSer для «BaseObject», а затем не создается таблица для BaseObject, что хорошо, но тогда я не могу легко выполнить поиск всех «BaseObjects», что плохо (но не обязательно).

Проблема с этим «решением» заключается в том, что, когда я добавляю приведенный ниже код для большего количества определений классов, чем таблица для класса «BaseObject», появляется снова (не знаю почему, может кто-нибудь объяснить?), И отношение внешнего ключа снова установить в таблицу «BaseObject».

Public Class BaseObject
    <Key()>
    <DatabaseGenerated(DatabaseGeneratedOption.None)>
    Public Overridable Property iId As Integer

    <Required()>
    Public Property iModUserId As Integer

    <ForeignKey("iModUserId")>
    Public Property ModUser As User

    <Required()>
    Public Property dtModDate As DateTime

    <InverseProperty("BaseObjects")>
    Public Overridable Property Group As ICollection(Of Group)
End Class

Public Class User
    Inherits BaseObject

    <Required()>
    Public Property sFirstName As String

    <Required()>
    Public Property sLastName As String
End Class

<Table("tGroups")>
Public Class Group
    Inherits BaseObject

    <InverseProperty("Groups")>
    Public Overridable Property BaseObjects As ICollection(Of BaseObject)
End Class

Есть ли способ исправить это, чтобы отношение внешнего ключа было задано для таблицы "Пользователь" (класс), а не для таблицы "BaseObject"?

Я пробовал использовать приведенный ниже Fluent API, но результат тот же:

modelBuilder.Entity(Of User)().HasRequired(Function(u) u.ModUser).WithMany().HasForeignKey(Function(u) u.iModUserId)

1 Ответ

0 голосов
/ 09 января 2012

Не думаю, что вы можете использовать отношение к базовому классу наследования TPC. Это не имеет смысла и ИМХО это не может работать. Отношение должно быть выражено в базе данных как любое другое действительное отношение = ссылочное ограничение и внешний ключ. Как база данных должна управлять связью с несуществующей таблицей? TPC означает, что не должно быть никакой таблицы для родительской сущности, поскольку все содержимое родительской сущности отображается в таблицу для каждой дочерней сущности, поэтому не может быть смоделировано самоссылочное отношение к родительской сущности. Это привело бы к специальному набору FK от производного объекта ко всем другим производным объектам. Поскольку EF не знает, как справиться с этим, это терпит неудачу.

Полагаю, вы должны либо изменить свой дизайн, либо использовать наследование TPT.

...