简体   繁体   中英

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!

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? 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?

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.
  • 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.
  • 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. 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

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

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

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)

数据库预览

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 . If a Bunk can only belong to one Room , then you already have the chosen Room through Bunk.Room . By adding another foreign key to Booking for Room , you're creating a double-link that will make things like deletions arduous.

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. 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()

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). This will require 2 calls to the database. First call to get the room, second to get the Bunks.

This will only work if you change your ICollection properties to be virtual:

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. 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. If this property is not virtual, then it can't do this, and therefore it won't work

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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