简体   繁体   English

ASP.net MVC 4 EF5中的代码优先方法混乱

[英]Code First Approach Confusion in ASP.net MVC 4 EF5

I've been struggling for the last 10 or so hours trying to figure out and research the best way to achieve the relational code first database structure and class architecture that I'm after. 在过去的十个小时左右的时间里,我一直在努力寻找并研究实现关系代码优先的数据库结构和类结构的最佳方法。

Unfortunately ASP and Google has defeated me so far! 不幸的是,到目前为止,ASP和Google击败了我!

I'll attach a UML diagram to better explain what I envision the system to do, I'm really just looking for an explanation on the approach I should be taking, where to keep certain functionality, if I need to create additional classes as View Models, Domain Models, How to link all of this into a Database Context, Do I need to create all the CRUD implementations myself? 我将附上一个UML图,以更好地解释我对系统的设想,实际上,我只是在寻找有关我应该采用的方法的说明,如果需要创建其他类(如View),则应保留某些功能。模型,领域模型,如何将所有这些链接到数据库上下文中,我是否需要自己创建所有CRUD实现? etc etc.. 等等等

(I've used ArrayList as I'm from a Java background and know that best, I've been reading into ICollections and IEnumerables but can't decide which one to use? (我从Java的背景开始就使用过ArrayList,并且最清楚的是,我一直在阅读ICollections和IEnumerables,但无法确定使用哪个?

UML图

From my previous attempts I have so far tried: 从我以前的尝试,到目前为止,我已经尝试过:

  • A single class implementing DbContext class which contains DbSet ' for all of the Room , Bunk and Booking classes. 一个实现DbContext类的类,其中包含所有RoomBunkBooking类的DbSet '。
  • A single domain class (is this right terminology?) for each "Entity" which stores the class data similar to the above, I've managed to generate databases from these with the help of add-migrations but the way it linked the Room and Bunk classes using an ICollection didn't seem to provide any way to access the bunks assosiated to a Room from the Room.Bunks ICollection when retrieving a bunk from the DB. 每个类似于上面存储类数据的“实体”的单个域类(这是正确的术语吗?),我已经设法借助add-migrations从这些数据库中生成数据库,但是它如何链接Room和使用ICollection Bunk类似乎没有提供任何方法来从Room.Bunks ICollection中访问与Room Room.Bunks
  • I also had RoomHelper and BunkHelper classes which used LINQ statements to attempt to retrieve various data manually as well as the standard CRUD methods. 我还拥有RoomHelperBunkHelper类,它们使用LINQ语句来尝试手动检索各种数据以及标准CRUD方法。 This seemed to get confusing and made me think that I might be missing something that's auto generated for me? 这似乎令人困惑,并让我觉得我可能会缺少为我自动生成的内容?

It's a lot but I'm really struggling with this, any help is really appreciated :) 很多东西,但是我真的很努力,任何帮助都非常感激:)

As some people have requested below is the code I have created 正如某些人要求的,以下是我创建的代码

Bunk.cs Bunk.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using TestApplication.Models.Enums;

namespace TestApplication.Models
{
    public class Bunk
    {
        [Key]
        public Int32 BunkId { get; set; }
        public BunkStatus BunkStatus { get; set; }
    }
}

Room.cs Room.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using TestApplication.Models.Enums;

namespace TestApplication.Models
{
    public class Room
    {
        [Key]
        public Int32 RoomId { get; set; }
        public String RoomName { get; set; }
        public Gender RoomGender { get; set; }
        public RoomStatus RoomStatus { get; set; }
        public ICollection<Bunk> Bunks { get; set; }
    }
}

DatabaseContext.cs DatabaseContext.cs

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;

namespace TestApplication.Models
{
    public class DatabaseContext : DbContext
    {
        public DbSet<Room> Rooms { get; set; }
        public DbSet<Bunk> Bunks { get; set; }
    }
}

This code has generated the below database structure, which doesn't allow me to access Room.Bunks.All() (as an example usage of the concept I'm misunderstanding) 此代码生成了以下数据库结构,该数据库结构不允许我访问Room.Bunks.All() (作为我误解的概念的示例用法)

数据库预览

These are the classes you would need: 这些是您需要的类:

public class Room
{
    [Key]
    public int RoomId { get; set; }

    public string RoomName { get; set; }

    public GenderEnum Gender { get; set; }

    public RoomStatusEnum RoomStatus { get; set; }

    public virtual ICollection<Bunk> Bunks { get; set; }

    // convenience
    public virtual ICollection<Booking> Bookings { get; set; }
}

public class Bunk
{
    [Key]
    public int BunkId { get; set; }

    public BunkStatusEnum BunkStatus { get; set; }

    [ForeignKey("Room")]
    public int RoomId { get; set; }
    public virtual Room Room { get; set; }

    // convenience
    public virtual ICollection<Booking> Bookings { get; set; }
}

public class Booking
{
    [Key]
    public int BookingId { get; set; }

    [ForeignKey("UserProfile")]
    public int UserProfileId { get; set; }
    public UserProfile UserProfile { get; set; }

    [ForeignKey("Bunk")]
    public int BunkId { get; set; }
    public Bunk Bunk { get; set; }

    public int Duration { get; set; }

    [ForeignKey("Preferred_Room")]
    public int RoomId { get; set; }
    public Room Preferred_Room { get; set; }

    public Decimal Price { get; set; }

    public BookStatusEnum BookingStatus { get; set; }
}

The only thing I would caution you with is the foreign key to Room in Booking . 我唯一要提醒您的是“ Booking Room的外键。 If a Bunk can only belong to one Room , then you already have the chosen Room through Bunk.Room . 如果一个Bunk只能属于一个Room ,那么您已经通过Bunk.Room选择了Room By adding another foreign key to Booking for Room , you're creating a double-link that will make things like deletions arduous. 通过向Booking for Room添加另一个外键,您将创建一个双链接,这将使删除工作变得很困难。

I'll expand on my comment above because after now posting your code, it seems that you have indeed not made the navigation properties virtual. 我将在上面的评论中进行扩展,因为在发布代码之后,看来您确实没有将导航属性虚拟化。

You need to get a room object from the database, using a query of some sort. 您需要使用某种查询从数据库中获取房间对象。 For example: 例如:

using (var context = new DatabaseContext()){
    var room = context.Rooms.First();
}

In the above example, you will end up with a room object, but the entity framework will not automatically pull back all related entities (ie the Bunks).. in a lot of cases this would be overkill, in some cases it would be impossible. 在上面的示例中,您最终将获得一个room对象,但是实体框架不会自动拉回所有相关实体(例如Bunks)。在很多情况下,这可能会过大,在某些情况下,这是不可能的。 You need to specifically tell the entity framework which related entities you want it to bring back. 您需要明确告知实体框架您希望带回哪些相关实体。 eg: 例如:

using (var context = new DatabaseContext()){
    var room = context.Rooms.Include("Bunks").First();
}

In this example, the entity framework will load the Bunks as part of the query, and you will be able to access the bunks by using the syntax room.Bunks() 在此示例中,实体框架将作为查询的一部分加载Bunks,您将能够使用语法room.Bunks()访问Bunks。

Finally, you can get the original example to work too if that's what you'd prefer. 最后,如果您愿意的话,您也可以使用原始示例。 You would take advantage of something called Lazy loading, whereby the entity framework will only load related entities when you first access the navigation property (that is room.Bunks). 您将利用一种称为“延迟加载”的功能,即实体框架仅在您首次访问导航属性(即room.Bunks)时才加载相关的实体。 This will require 2 calls to the database. 这将需要2次调用数据库。 First call to get the room, second to get the Bunks. 第一次打电话来获得房间,第二次得到铺位。

This will only work if you change your ICollection properties to be virtual: 仅当将ICollection属性更改为虚拟时,这才起作用:

public ICollection<Bunk> Bunks { get; set; }

needs to become 需要成为

public virtual ICollection<Bunk> Bunks { get; set; }

This is because entity framework needs to know when you first access the Bunks collection. 这是因为实体框架需要知道您何时首次访问Bunks集合。 Entity framework does this by returning an object derived from the Room class, instead of your Room class, and it overrides the Bunks property with code which runs when you first access it. 实体框架通过返回从Room类(而不是Room类)派生的对象来实现此目的,并且它使用首次访问时运行的代码覆盖Bunks属性。 If this property is not virtual, then it can't do this, and therefore it won't work 如果此属性不是虚拟属性,则它将无法执行此操作,因此它将无法正常工作

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM