2011-12-16 46 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>