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.buyers
, Buyers.first.items
和Buyer.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) } @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)