2

Arena と Regulator という 2 つのエンティティがあり、それらの間には多対多の関係があります。EFコードで最初に受け入れられたソリューションと思われるものを実装しました(以下を参照)。

ユーザーがレギュレーターを作成するときに、1 つまたは複数のアリーナ (おそらくチェック ボックスまたは複数選択リストを使用) を選択できるように、コントローラー ビューの実装に行き詰まっています。また、アリーナを作成するときに、1 つまたは複数のレギュレーターを選択されました。

1 対多の関係の場合のように、MVC4 がコントローラーとビューを生成する方法はありますか?

編集: 最初のコメントから、選択したアリーナをレギュレーター オブジェクトの Arenas ナビゲーション プロパティに追加できることがわかりました。選択リストを編集 (および作成) ビューに追加し、コントローラーで変更を加える方法を見つけることができませんでした。誰でも例を提供できますか?

EDIT2: EF が実際にリレーションシップを更新した場合に機能する Edit アクションのコードがあります (regulator.ArenaIDs は、MultiSelectList から選択したアイテム IDS を取得するために、レギュレーター クラスに追加した整数のリストです):

<HttpPost()> _
<ValidateAntiForgeryToken()> _
Function Edit(ByVal regulator As Regulator) As ActionResult
    If ModelState.IsValid Then
        For Each i In regulator.ArenaIDs
            regulator.Arenas.Add(db.Arenas.Find(i))
        Next
        db.Entry(regulator).State = EntityState.Modified
        db.SaveChanges()
        Return RedirectToAction("Index")
    End If

    Return View(regulator)
End Function

VS 2012 と EF 5.0 を使用しています

これが私の実装です:

Public Class Arena
    Public Property Id As Integer
    Public Property Name As String
    Public Overridable Property Regulators() As ICollection(Of Regulator)
End Class

Public Class Regulator
    Public Property Id As Integer
    Public Property Name As String
    Public Overridable Property Arenas() As ICollection(Of Arena)
End Class

次の DbContext で

Public Class TslilContext
    Inherits DbContext
    Public Property Arenas As DbSet(Of Arena)
    Public Property Regulators As DbSet(Of Regulator)

    Protected Overrides Sub OnModelCreating(ByVal modelBuilder As DbModelBuilder)
        modelBuilder.Entity(Of Arena)(). _
            HasMany(Function(c) c.Regulators). _
            WithMany(Function(p) p.Arenas). _
            Map(Function(m)
                    m.MapLeftKey("ArenaId")
                    m.MapRightKey("RegulatorId")
                    m.ToTable("Tiers")
                End Function)
    End Sub
4

3 に答える 3

2

多くの調査の後、私は EF が関係を更新できないことを理解しました - 非常に驚くべきことであり、残念なことです。明らかに、提案された解決策は、結合テーブルとナビゲーション プロパティを手動で更新することですが、あまり良くありません。NHibernate はどうやらこれをすぐに実行できるようで、次にこれが必要になったときに十分に調査するつもりです。

幸いなことに、Refactor(This)から、拡張メソッドを DbContext に追加して、複雑な関係の自動更新を可能にする、真に優れたソリューションに出会いました。Nugetパッケージもあります!

だからここに私の完全な解決策があります:

選択したアリーナの ID を取得する整数リストを Regulator クラスに追加しました。

Public Class Regulator
    Public Property Id As Integer
    Public Property Name As String
    Public Property ArenaIDs() As ICollection(Of Integer)
    Public Overridable Property Arenas() As ICollection(Of Arena)
End Class

GET Edit アクションでは、これが処理され、MultiSelectList が作成されます。

' GET: /Regulator/Edit/5

Function Edit(Optional ByVal id As Integer = Nothing) As ActionResult
    Dim regulator As Regulator = db.Regulators.Find(id)
    If IsNothing(regulator) Then
        Return HttpNotFound()
    End If
    For Each a In regulator.Arenas
        regulator.ArenaIDs.Add(a.Id)
    Next
    ViewBag.MultiSelectArenas = New MultiSelectList(db.Arenas.ToList(), "Id", "Name", regulator.ArenaIDs)
    Return View(regulator)
End Function

また、MultiSelectList はビューで使用されます。

    <div class="editor-field">
        @Html.ListBoxFor(Function(m) m.ArenaIDs, ViewBag.MultiSelectArenas)
        @Html.ValidationMessageFor(Function(model) model.Arenas)
    </div>

POST Edit アクションでは、セレクション ID が取得され、Arenas コレクションの更新に使用されます。次に、EF ではできないことを実行し、リレーションシップを更新する UpdateGraph 拡張メソッドに魔法がかかります。

' POST: /Regulator/Edit/5

<HttpPost()> _
<ValidateAntiForgeryToken()> _
Function Edit(ByVal regulator As Regulator) As ActionResult
    If ModelState.IsValid Then
        For Each i In regulator.ArenaIDs
            regulator.Arenas.Add(db.Arenas.Find(i))
        Next

        db.UpdateGraph(Of Regulator)(regulator, Function(map) map.AssociatedCollection(Function(r) r.Arenas))

        db.SaveChanges()
        Return RedirectToAction("Index")
    End If
于 2013-07-05T19:09:06.500 に答える
1

ここでの問題は、EF がリレーションシップを更新しないことではなく、自動的に更新しないことです。

必要なことは、レギュレーターの現在のアリーナを取得してから、リストをたどって、新しいリストにない既存のエントリを削除することです。次に、まだ存在しないエントリを追加する必要があります。次に、変更を保存します。

これは機能しますが、問題は、既存の関係をやみくもに追加しようとしているか、存在しない関係を更新しようとしていることです。実際に既存のリストを取得し、どの関係を追加または削除するかを判断する必要があります。

あなたが自分に合った解決策をすでに見つけていることは理解しています。ここでの私のポイントは、厳密な EF ベースの解決策を実行しようとしている場合、間違った方法で進んでいたということです。

別のオプションは、すべての関係を削除して SaveChanges し、新しいセットを追加して SaveChanges を再度追加することだと思います。オーバーラップがある場合、これはすでに存在するものを削除しますが、かなり単純明快です。

もう 1 つのオプションは、既存のものを削除し、それらを再度追加してから、元のセットを調べて、以前に存在していたものの状態を Modified または None に変更することです。もう少し複雑ですが、保存時にのみ必要です。

于 2013-07-05T21:44:55.793 に答える