2011-12-16 47 views
8

在.NET Entity Framework中,创建具有额外属性(除id之外)的(自定义)连接表的最佳方式和/或将此连接表与其他人通过单独模式?在Ruby on Rails的,我们可以有连接表的模型,如:Rails在ASP.NET MVC3中具有许多等价的功能在.NET MVC3中

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的“添加关联”对话框中,如果我们选择多重性为*(许多),则没有选择连接表(使用模型)的选项。有没有办法手动做到这一点?

回答

6

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

下面是一个例子:

学生 - > StudentFloor < - 楼

public class Student 
{ 
    public int Id { get; set; } 
    // ... properties ... 

    // Navigation property to your link table 
    public virtual ICollection<StudentFloor> StudentFloors { get; set; } 

    // If you wanted to have a property direct to the floors, just add this: 
    public IEnumerable<Floor> 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<StudentFloor> StudentFloors { get; set; } 
} 
+0

感谢您的输入。请检查更新部分,并让我知道如果控制器中的代码可以做得更薄更时尚。 – 2012-01-26 19:53:35

0

Lenient的回答更新:

我们还可以使用Model第一种方法创建两个一对多关系。无论哪种方式,我们都不能像在纯粹的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<Floor>(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); 
} 

在查看,我们可以发送FloorModelView的对象,如:

@model ManyToManyAutoGen.Models.FloorViewModel 

@{ 
    ViewBag.Title = "Create"; 
} 

<h2>Create</h2> 

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script> 
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script> 

@using (Html.BeginForm()) { 
    @Html.ValidationSummary(true) 
    <fieldset> 
     <legend>Floor</legend> 

     @Html.Partial("_CreateOrEdit", Model) 

     <p> 
      <input type="submit" value="Create" /> 
     </p> 
    </fieldset> 
} 

<div> 
    @Html.ActionLink("Back to List", "Index") 
</div> 

最后,_CreateOrEdit部分看起来像:

@model ManyToManyAutoGen.Models.FloorViewModel 

@* This partial view defines form fields that will appear when creating and editing entities *@ 

<div class="editor-label"> 
    @Html.LabelFor(model => model.MyFloor.FloorName) 
</div> 
<div class="editor-field"> 
    @Html.EditorFor(model => model.MyFloor.FloorName) 
    @Html.ValidationMessageFor(model => model.MyFloor.FloorName) 
</div> 

<div class="editor-label"> 
    @Html.LabelFor(model => model.MyStudents) 
</div> 
<div class="editor-field"> 
    @Html.ListBoxFor(model => model.MyStudents, Model.StudentsList) 
    @Html.ValidationMessageFor(model => model.MyStudents) 
</div> 

<div class="editor-label"> 
    @Html.LabelFor(model => model.Join.First().Room) 
</div> 
<div class="editor-field"> 
    @Html.EditorFor(model => model.Join.First().Room) 
    @Html.ValidationMessageFor(model => model.Join) 
</div>