Rails在ASP.NET MVC3中具有多个等价物

在.NETentity framework中,具有额外属性(除了ids)和/或通过单独模型将此连接表与其他属性关联的(自定义)连接表的最佳方法是什么? 在Ruby on Rails中,我们可以为连接表建立一个模型,例如:

Item.rb (model) :has_many => :buyers, :through=>:invoice ... Buyers.rb (model) :has_many => :items, :through=>:invoice ... Invoice.rb (model) :belongs_to :item :belongs_to :buyer .... 

然后我们可以使用: Item.first.buyersBuyers.first.itemsBuyer.create(:items=>Item.create(:name=>'random'))等,就像我们使用自动连接表而没有模型一样(使用has_and_belongs_to_many)。

在Visual Studio 2010的“添加关联”对话框中,如果我们选择多重性为*(多个),则无法选择连接表(带有模型)。 有没有办法手动完成?

是的,你可以得到非常接近的东西。 我不太确定如何在设计器中设置它,因为我只使用codefirst。

这是一个例子:

学生 – >学生楼层< - 楼层

 public class Student { public int Id { get; set; } // ... properties ... // Navigation property to your link table public virtual ICollection StudentFloors { get; set; } // If you wanted to have a property direct to the floors, just add this: public IEnumerable Floors { get { return StudentFloors.Select(ft => ft.Floor); } } } 

链接表:

 public class StudentFloor { #region Composite Keys // Be sure to set the column order and key attributes. // Convention will link them to the navigation properties // below. The database table will be created with a // compound key. [Key, Column(Order = 0)] public int StudentId { get; set; } [Key, Column(Order = 1)] public int FloorId { get; set; } #endregion // Here's the custom data stored in the link table [Required, StringLength(30)] public string Room { get; set; } [Required] public DateTime Checkin { get; set; } // Navigation properties to the outer tables [Required] public virtual Student Student { get; set; } [Required] public virtual Floor Floor { get; set; } } 

最后,多对多的另一面:

 public class Floor { public int Id { get; set; } // ... Other properties. public virtual ICollection StudentFloors { get; set; } } 

更新到宽恕的答案:

我们还可以使用模型第一种方法创建两个一对多关系。 无论哪种方式,我们都不能在纯M2M关系中发生模型绑定(没有有效载荷或纯连接表–PJT)。

此外,在(脚手架)控制器中,我们可以根据要求使用CRUD操作的视图模型。 据说,我们有一个FloorViewModel,其定义如下:

 public class FloorViewModel { private Model2Container context = new Model2Container(); [Display(Name = "Student List")] [Required(ErrorMessage = "Please select atleast one student from the list.")] public int[] MyStudents { get; set; } public Floor MyFloor { get; set; } public MultiSelectList StudentsList { get; set; } public StudentFloorJoin Join { get; set; } } 

控制器中的创建操作将是:

 // // GET: /Floor/Create public ActionResult Create() { var model = new FloorViewModel() { StudentsList = new MultiSelectList(context.Students, "Id", "Name") }; return View(model); } // // POST: /Floor/Create [HttpPost] public ActionResult Create(FloorViewModel floor) { if (ModelState.IsValid) { context.Floors.Add(floor.MyFloor); context.SaveChanges(); } foreach (var student in floor.MyStudents) { context.StudentFloorJoins.Add(new StudentFloorJoin() { Student = context.Students.Find(student), Floor = floor.MyFloor, Room = floor.Join.Room }); } if (ModelState.IsValid) { context.SaveChanges(); return RedirectToAction("Index"); } context.Floors.Remove(floor.MyFloor); floor.StudentsList = new MultiSelectList(context.Students, "Id", "Name", floor.MyStudents); return View(floor); } 

并且编辑操作将类似于:

 // // GET: /Floor/Edit public ActionResult Edit(int id) { Floor floor = context.Floors.Single(x => x.Id == id); int[] ids = (from i in floor.StudentFloorJoins select i.Student.Id).ToArray(); var model = new FloorViewModel() { StudentsList = new MultiSelectList(context.Students, "Id", "Name", ids), MyFloor = floor, Join = new StudentFloorJoin() { Room = floor.StudentFloorJoins.Count == 0 ? "" : floor.StudentFloorJoins.First().Room } }; return View(model); } // // POST: /Floor/Edit [HttpPost] public ActionResult Edit(FloorViewModel floor) { if (ModelState.IsValid) { var item = floor.MyFloor; var itemEntry1 = context.Entry(item); itemEntry1.State = EntityState.Modified; var query = (from i in context.StudentFloorJoins where i.Floor.Id == item.Id select i.Id); foreach (var studentfloor in query) { context.StudentFloorJoins.Remove(context.StudentFloorJoins.Find(studentfloor)); } context.SaveChanges(); foreach (var student in floor.MyStudents) { context.StudentFloorJoins.Add(new StudentFloorJoin() { Student = context.Students.Find(student), Floor = floor.MyFloor, Room = floor.Join.Room }); } context.SaveChanges(); return RedirectToAction("Index"); } floor.StudentsList = new MultiSelectList(context.Students, "Id", "Name", floor.MyStudents); return View(floor); } 

在View中,我们可以发送FloorModelView的对象,如:

 @model ManyToManyAutoGen.Models.FloorViewModel @{ ViewBag.Title = "Create"; } 

Create

@using (Html.BeginForm()) { @Html.ValidationSummary(true)
Floor @Html.Partial("_CreateOrEdit", Model)

}
@Html.ActionLink("Back to List", "Index")

最后,_CreateOrEdit部分看起来像:

 @model ManyToManyAutoGen.Models.FloorViewModel @* This partial view defines form fields that will appear when creating and editing entities *@ 
@Html.LabelFor(model => model.MyFloor.FloorName)
@Html.EditorFor(model => model.MyFloor.FloorName) @Html.ValidationMessageFor(model => model.MyFloor.FloorName)
@Html.LabelFor(model => model.MyStudents)
@Html.ListBoxFor(model => model.MyStudents, Model.StudentsList) @Html.ValidationMessageFor(model => model.MyStudents)
@Html.LabelFor(model => model.Join.First().Room)
@Html.EditorFor(model => model.Join.First().Room) @Html.ValidationMessageFor(model => model.Join)