如何为多对多关系创建viewModel对象

时间:2015-11-29 21:24:45

标签: asp.net-mvc entity-framework asp.net-mvc-5

我是ASP.NET的新手,目前正在开发一个简单的应用程序来显示人员和他们的爱好列表。我有以下课程:

public class Hobby
{
    public int HobbyID                            {get;set;}
    public string Name                            {get;set;}
    public string Type                            {get;set;}
    public ICollection<PersonHobby> PersonHobbies {get;set;}
}

public class Person
{
    public int PersonID                           {get;set;}
    public int Age                                {get;set;}
    public string Name                            {get;set;}
    public ICollection<PersonHobby> PersonHobbies {get;set;}
}

public class PersonHobby
{
    public int PersonHobbyID                      {get;set;}
    public int PersonID                           {get;set;}
    public int HobbyID                            {get;set;}
}

在查看某人的详细信息页面时,我还需要展示他们的爱好。我做了一些研究,发现ViewModels是实现这一目标的好方法。所以我创建了一个,但我不确定我是否做得正确:

public class PersonHobbiesViewModel
{
    public Person Person                          {get;set;}
    public IEnumerable<PersonHobby> PersonHobbies {get;set;}
    public IEnumerable<Hobby> Hobbies             {get;set;}
}

此时我知道我需要在控制器的Details方法中创建一个viewmodel对象并用数据填充它,但我不知道如何浏览不同的表。我有这个:

public ActionResult Details(int? id)
{
    var viewModel = new PersonHobbiesViewModel();
    viewModel.Person = db.Person.find(id);
    viewModel.Hobbies = ???

    return View(viewModel);
}

另一方面,如果我走向完全错误的方向,请告诉我!提前谢谢。

2 个答案:

答案 0 :(得分:2)

首先,您可能想做的是,稍微更改您的实体模型,让EF6为您处理多种复杂性。

您的新模型可能如下所示:

public class Hobby
{
    public int HobbyID { get; set; }
    public string Name { get; set; }
    public string Type { get; set; }
    public Person Person { get; set; }
}

public class Person
{
    public int PersonID { get; set; }
    public int Age { get; set; }
    public string Name { get; set; }
    public ICollection<Hobby> Hobbies { get; set; }
}

您的上下文可能如下:

public class MyContext : DbContext
{
    public DbSet<Hobby> Hobbies { get; set; }
    public DbSet<Person> People { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

        modelBuilder.Entity<Hobby>()
                    .HasRequired<Person>(s => s.Person)
                    .WithMany(s => s.Hobbies)
                    .HasForeignKey(s => s.PersonId);
    }
}

然后,当您创建模型时,您可以简单地查询它:

var person = db.People.Include(c => c.Hobbies).SingleOrDefault(x => x.PersonID == id);

var viewModel = new PersonHobbiesViewModel();

viewModel.Person = person;
viewModel.Hobbies = person.Hobbies;

return View(viewModel);

请仔细阅读以下有关complex entity modelsreading from them的教程,它们涵盖相同的内容。

聚苯乙烯。我还没有测试过这个。

答案 1 :(得分:1)

@shenku的回答有正确的方法来映射实体。但如果不考虑命名约定,则没有必要。

另外,Entity Framework有很多c#的面向对象编程基础知识。这意味着如果您将人物对象从控制器传递到视图,您可以在视图中访问您的实体,如下所示。

//Controller
var person = db.People.Include(c => c.Hobbies).SingleOrDefault(x => x.PersonID == id);
return View(person);

@*View Page*@
@using Project.Models
@*  prints Person Name and Age  *@
@Model.Name @Model.age 
@*  prints Hobby Names of Person
 @foreach (var item in Model)
{                    
@item.name
}

您的评论中的“循环引用”已经回答了您自己的问题。

所以你不需要PersonHobby类,Entity框架会自动为你创建这个表。这种魔力的发生是因为你已经将爱好和人物定义为他们自己的类的集合。

此外,根据您的情况,您不需要viewModel。只是传递人或爱好的对象。不要传递Icollection,因为它在您编写db.People.Include(c => c.Hobbies)时已经加载了。你也可以将类定义为'virtual',这样它就可以加载没有include方法的实体。(延迟加载)