MVC4控制器多对多的关系 [英] MVC4 controller with Many to Many relationship

查看:294
本文介绍了MVC4控制器多对多的关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个实体,竞技场和稳压器,它有很多他们之间有很多关系。我已经实现了什么似乎是EF code首先接受的解决方案(见下文)。

我现在坚持实现控制器的看法,这样当用户创建一个稳压器,他可以选择一个或多个阿里纳斯(可能与复选框或多选列表),而当他们创造一个舞台,一个或多个监管机构可以选择。

有没有办法为MVC4生成我控制器和视图,就像它为一对多的关系?

编辑:从最初的评论,我现在明白,我可以选择的竞技场添加到监管对象的阿里纳斯导航属性。我一直没能找到既增加了选择列表编辑(和创建)的意见,然后进行控制器的变化的方式。任何人都可以提供一个例子吗?

EDIT2:我有code因为如果EF确实更新的关系,应该工作的编辑操作(regulator.ArenaIDs是我加入调节类整数列表,以获得所选择的项目IDS从MultiSelectList)

 < HttpPost()> _
&所述; ValidateAntiForgeryToken()> _
功能编辑(BYVAL调节器调节器)作为的ActionResult
    如果ModelState.IsValid然后
        对于每一个我在regulator.ArenaIDs
            regulator.Arenas.Add(db.Arenas.Find(I))
        下一个
        db.Entry(调节).STATE = EntityState.Modified
        db.SaveChanges()
        返回RedirectToAction(指数)
    万一    返回查看(调节)
结束功能

我使用VS 2012和EF 5.0

下面是我的实现:

 公共类竞技场
    公共属性ID作为整数
    公共属性名称作为字符串
    公众可重写属性调节器()作为ICollection的(稳压)
末级公共类稳压器
    公共属性ID作为整数
    公共属性名称作为字符串
    公众可重写属性阿里纳斯()作为ICollection的(竞技场)
末级

用下面的DbContext

 公共类TslilContext
    继承的DbContext
    公共属性阿里纳斯作为DbSet(竞技场)
    公共财产监管者DbSet(稳压)    受保护的覆盖子OnModelCreating(BYVAL模型构建器作为DbModelBuilder)
        modelBuilder.Entity(主场),()。 _
            的hasMany(功能(三)c.Regulators)。 _
            WithMany(功能(P)p.Arenas)。 _
            地图(功能(M)
                    m.MapLeftKey(ArenaId)
                    m.MapRightKey(RegulatorId)
                    m.ToTable(层级)
                结束功能)
    结束小组


解决方案

很多的研究,我已经认识到EF不能更新的关系后 - 非常惊讶和失望。 Aparently,建议的解决方案是连接表和导航性能手动更新 - 不是很好。 NHibernate的显然没有做到这一点的开箱,我完全打算调查下一次我需要这个。

幸运的是我遇到了一个真正伟大的解决方案,从<一个href=\"http://refactorthis.word$p$pss.com/2012/12/11/introducing-graphdiff-for-entity-framework-$c$c-first-allowing-automated-updates-of-a-graph-of-detached-entities/\"相对=nofollow>重构(这),增加了一个扩展方法的DbContext,让复杂的关系自动更新。甚至有一个的NuGet包!

因此​​,这里是我的完整的解决方案:

我添加了一个整数列表中稳压器类,获取选定阿里纳斯的ID。

 公共类稳压器
    公共属性ID作为整数
    公共属性名称作为字符串
    公共财产ArenaIDs()作为ICollection的(整数)
    公众可重写属性阿里纳斯()作为ICollection的(竞技场)
末级

在GET编辑动作,这是照顾和MultiSelectList创建:

 'GET:/稳压器/编辑/ 5编辑功能(可选BYVAL ID作为整数= Nothing)作为的ActionResult
    昏暗的监管作为监管= db.Regulators.Find(ID)
    如果IsNothing(调节)然后
        返回HttpNotFound()
    万一
    为每个在regulator.Arenas
        regulator.ArenaIDs.Add(a.Id)
    下一个
    ViewBag.MultiSelectArenas =新MultiSelectList(db.Arenas.ToList(),ID,姓名,regulator.ArenaIDs)
    返回查看(调节)
结束功能

而MultiSelectList在视图中使用:

 &LT; D​​IV CLASS =主编场&GT;
        @ Html.ListBoxFor(功能(M)m.ArenaIDs,ViewBag.MultiSelectArenas)
        @ Html.ValidationMessageFor(功能(模型)model.Arenas)
    &LT; / DIV&GT;

在POST编辑动作的选择ID被检索并用于更新阿里纳斯集合。再神奇自带的与做什么EF不能和更新的关系!在UpdateGraph扩展方法

 'POST:/稳压器/编辑/ 5&所述; HttpPost()&GT; _
&所述; ValidateAntiForgeryToken()&GT; _
功能编辑(BYVAL调节器调节器)作为的ActionResult
    如果ModelState.IsValid然后
        对于每一个我在regulator.ArenaIDs
            regulator.Arenas.Add(db.Arenas.Find(I))
        下一个        db.UpdateGraph(调节器)(调节器,功能(图)map.AssociatedCollection(功能(R)r.Arenas))        db.SaveChanges()
        返回RedirectToAction(指数)
    万一

I have the two entities, Arena and Regulator, which have a many to many relationship between them. I have implemented what seems to be the EF code first accepted solution (see below).

I am now stuck with implementing the controller views, so that when a user creates a regulator, he can select one or more arenas (probably with check boxes or multi select list), and when they create an arena, one or more regulators can be selected.

Is there a way for MVC4 to generate the controller and views for me, like it does for one to many relationships?

EDIT: From the initial comments, I now understand that I can add the selected arena to the Arenas navigation property of the regulator object. I have not been able to find the way to both add the selection list to the Edit (and Create) views, and then make the changes in the controller. Can anyone supply an example?

EDIT2: I have code for the Edit actions that should work if EF did indeed update relationships (regulator.ArenaIDs is a list of integers I added to the regulator class, to get the selected item IDS from the MultiSelectList):

<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

I am using VS 2012 and EF 5.0

Here is my implementation:

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

with the following 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

解决方案

After a lot of research I have understood that EF cannot update relationships - very surprising and disappointing. Aparently, the suggested solution is a manual update of the join table and navigation properties - not very good. NHibernate apparently does do this out of the box and I fully intend to investigate next time I need this.

Luckily I came across a truly great solution from Refactor(This) that adds an extension method to DbContext, allowing automated updating of complex relationships. There is even a Nuget package!

So here is my full solution:

I've added an integer list to the Regulator class, which gets the IDs of the selected Arenas.

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

In the GET Edit action, this is taken care of and a MultiSelectList is created:

' 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

And the MultiSelectList is used in the View:

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

In the POST Edit action the selection IDs are retrieved and used to update the Arenas collection. Then the magic comes in the with the UpdateGraph extension method that does what EF can not and updates the relationship!

' 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

这篇关于MVC4控制器多对多的关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆