Database design using code-first approach in Entity Framework - entity-framework

I am designing a database for tests (say #school) and I am not sure how to go about the seeding the database (I am using the code-first approach and the models are as below)
My models are as follows:
Levels -> Subjects -> Chapters -> Questions -> Options
If I have to seed, I would need to create a level and a list of subjects, which in turn would need list of chapters which in turn would need list of questions and then list of options.
This is the code of the models:
//Level
public class Level
{
public Level()
{
Subjects = new List<Subject>();
}
public int id { get; set; }
public string Name { get; set; }
//Navigate
public virtual ICollection<Subject> Subjects { get; set; }
}
//Subject
public class Subject
{
public Subject()
{
Chapters = new List<Chapter>();
}
public int id { get; set; }
public string Name { get; set; }
public int LevelId { get; set; }
//Navigate
public virtual Level Level { get; set; }
public virtual ICollection<Chapter> Chapters { get; set; }
}
// Chapter
public class Chapter
{
public Chapter()
{
Questions = new List<Question>();
}
public int id { get; set; }
public string Name { get; set; }
public int SubjectId { get; set; }
public int LevelId { get; set; }
//Navigate
public virtual Subject Subject { get; set; }
public virtual Level Level { get; set; }
public virtual ICollection<Question> Questions { get; set; }
}
Any help would be appreciated

Related

EF Core Many-to-many table to another table

I have a question regarding Many to Many tables using EF Core.
Assume I have the below situation:
public class Book
{
public int BookId { get; set; }
public string Title { get; set; }
public Author Author { get; set; }
public ICollection<BookCategory> BookCategories { get; set; }
}
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public ICollection<BookCategory> BookCategories { get; set; }
}
public class BookCategory
{
public int BookId { get; set; }
public Book Book { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
}
Now, assume that I want to have another table called "Contracts" which should be a child of "BookCategory".
How can I create this relationship?

EF Core 2.1. Loading nested entities with joining tables

I have these models:
public class Transfer
{
public Article Article { get; set; }
public Branch BranchFrom { get; set; }
public Branch BranchTo { get; set; }
public User User { get; set; }
}
public class Article
{
public int Id{ get; set; }
public string Description { get; set; }
}
public class Branch
{
public int Id { get; set; }
public string Address { get; set; }
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
I need to get a list of all transfers made by a specific user, and load all it's related entities (BranchFrom, BranchTo, Article, User).
In EF 6 I was able to do it easily with this code:
_dbContext.Transfer.Include(x=>x.BranchFrom).Include(x=>x.BranchTo).Include(x=>x.Article).Include(x=>x.User).Where(x=>x.User.Id == userId).ToListAsync();
Given that in EF Core 2.1 you must define the joining tables I added them as follows:
public class TransferUser
{
public int TransferId { get; set; }
public int UserId { get; set; }
public Transfer Transfer { get; set; }
public User User { get; set; }
}
public class TransferArticle
{
public int TransferId { get; set; }
public int ArticleId { get; set; }
public Transfer Transfer { get; set; }
public Article Article { get; set; }
}
public class TransferBranchFrom
{
public int TransferId { get; set; }
public int BranchId { get; set; }
public Transfer Transfer { get; set; }
public Branch Branch { get; set; }
}
public class TransferBranchTo
{
public int TransferId { get; set; }
public int BranchId { get; set; }
public Transfer Transfer { get; set; }
public Branch Branch { get; set; }
}
And because of that I modified the Transfer model to be like this:
public class Transfer
{
public TransferArticle TransferArticle { get; set; }
public TransferBranch TransferBranchFrom { get; set; }
public TransferBranch TransferBranchTo { get; set; }
public TransferUser TransferUser { get; set; }
}
Now I don't know how the query needs to be.
I was doing it like this and it works, but only loads the transfer and the user
_dbContext.Transfer.Include(x=>x.TransferUser).Where(x=>x.TransferUser.UserId == userId).ToListAsync();
When I add another table then it doesnt work and throws an exception:
_dbContext.Transfer.Include(x=>x.TransferUser).Include(x=>x.TransferBranchFrom).Where(x=>x.TransferUser.UserId == userId).ToListAsync();
I cannot find any examples on how to load all the entities for this scenario

EF code first model not in sync with database

My EF Code First model for some reason is not in sync with the db. I'm getting this error:
{"Invalid column name 'Type_Id1'."}
The field is actually called 'Type_Id' so I'm not sure from where that 1 comes up. I have the table column called as Type_Id and also I've added a Type_Id in my type entity model.
Why might I be getting that error message, plus why I'm getting 1 at the end of the name?
Update
My Task class:
public class Task
{
public Task()
{
Language = 1;
Grades = new HashSet<Grade>();
Categories = new HashSet<Category>();
Subjects = new HashSet<Subject>();
Rooms = new Collection<Room>();
Tools = new Collection<Tool>();
}
[Key]
public int Id { get; set; }
public string Description { get; set; }
public virtual TaskType Type { get; set; }
public string Rules { get; set; }
[Required]
[StringLength(200), MinLength(1)]
public string Name { get; set; }
public int PreperationTime { get; set; }
public int InstructionTime { get; set; }
public int TaskTime { get; set; }
public int Type_Id { get; set; }
public string VideoLink { get; set; }
[Required]
public int Language { get; set; }
public int? MinimumParticipants { get; set; }
public int? MaximumParticipants { get; set; }
public int? Rating { get; set; }
[Required]
public string CreatedBy { get; set; }
public virtual ICollection<Grade> Grades { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public virtual ICollection<Subject> Subjects { get; set; }
public virtual ICollection<Room> Rooms { get; set; }
public virtual ICollection<Tool> Tools { get; set; }
}
DBContext class:
public ApplicationDbContext() : base("DefaultConnection", false)
{
}
public DbSet<Task> Tasks { get; set; }
public DbSet<TaskType> TaskTypes { get; set; }
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
You need to add the FK attribute on your navigation property. EF is creating Type_Id1 because Type_Id already exists (although it can't tell by convention it is the FK).
[ForeignKey("Type_Id")]
public virtual TaskType Type { get; set; }
https://msdn.microsoft.com/en-us/data/jj591583.aspx#Relationships

EF Code First 6 and many-to-many with entity mapping

Following the example in this question: How to create a many-to-many mapping in Entity Framework? I would like to have a table mapping where I can add or remove many-to-many relationships without having to go through the Media or Contract entities.
Essentially, I would like to have:
public class Media // One entity table
{
public int Id { get; set; }
public string Name { get; set; }
public bool Enabled { get; set; }
public virtual ICollection<Contract> Contracts { get; set; }
}
public class Contract // Second entity table
{
public int Id { get; set; }
public string Code { get; set }
public virtual ICollection<Media> Medias { get; set; }
}
public class ContractMedia // Association table implemented as entity
{
public Media Media { get; set; }
public int MediaId { get; set; }
public Contract Contract { get; set; }
public int ContractId { get; set; }
}
Is it possible to configure this scenario using the FluentAPI?
afaik not with the ContractMedia entity, but you can:
public class Media // One entity table
{
public int Id { get; set; }
public string Name { get; set; }
public bool Enabled { get; set; }
public virtual ICollection<ContractMedia> Contracts { get; set; }
}
public class Contract // Second entity table
{
public int Id { get; set; }
public string Code { get; set }
public virtual ICollection<ContractMedia> Medias { get; set; }
}
public class ContractMedia // Association table implemented as entity
{
public Media Media { get; set; }
public int MediaId { get; set; }
public Contract Contract { get; set; }
public int ContractId { get; set; }
}
or
public class Media // One entity table
{
public int Id { get; set; }
public string Name { get; set; }
public bool Enabled { get; set; }
public virtual ICollection<Contract> Contracts { get; set; }
}
public class Contract // Second entity table
{
public int Id { get; set; }
public string Code { get; set }
public virtual ICollection<Media> Medias { get; set; }
}
that will lead to the creation of a non mapped association table in the database.

Entity Framework : get related entities

I created a WCF service with Entity Framework.
I have 2 tables : Theaters and Locality. Locality as a foreign key in Theaters.
My method :
public theater[] GetTheaters()
{
using (Entities context = new Entities())
{
return context.theater.ToArray();
}
}
I have to remove the "virtual" keyword from "public virtual locality locality { get; set; }" in my theater class. Otherwise, I get a CommunicationException.
But when I do that, I get my list of theaters but the locality is null...
How can I get the locality ?
Thanks
My model class ( I also have other entities) :
public partial class locality
{
public locality()
{
this.theater = new HashSet<theater>();
}
public int idLocality { get; set; }
public int npa { get; set; }
public string locality1 { get; set; }
public ICollection<theater> theater { get; set; }
}
public partial class theater
{
public theater()
{
this.session = new HashSet<session>();
}
public int idTheater { get; set; }
public string name { get; set; }
public string address { get; set; }
public int idLocality { get; set; }
public double latitude { get; set; }
public double longitude { get; set; }
public int seats { get; set; }
public string phone { get; set; }
public string email { get; set; }
public bool threeD { get; set; }
public locality locality { get; set; }
public ICollection<session> session { get; set; }
}
Here is the error that I get :
"Object graph for type 'locality' contains cycles and cannot be serialized if reference tracking is disabled.
EDIT :
The solution that I found :
In my locality class, I had a Collection of theaters.
I had to add "private to the setter like this :
" public ICollection theater { get; private set; }"
So it works, but I still have a problem, I can't access to the theaters from the locality entity anymore. (no more bi-directional)
If you want to force related entities to load, you can use the Include method to do so. By default, related entities are loaded Lazily.
Your example would be:
public theater[] GetTheaters()
{
using (Entities context = new Entities())
{
return context.theater.Include(t=>t.Locality).ToArray();
}
}
You can use eager loading or explicit loading. With eager loading you use the Include extension method:
return context.Theater.Include(t => t.Locality).ToArray();
You're missing the correct annotations to create the relationships. See the code below. (or create the relationships yourself if using the FluentAPI)
Look for the [Key] and [ForeignKey] annotations, as well as the virtual keyword.
public partial class locality
{
public locality()
{
//this.theater = new HashSet<theater>();
}
[Key]
public int idLocality { get; set; }
public int npa { get; set; }
public string locality1 { get; set; }
public virtual ICollection<theater> theaters { get; set; }
}
public partial class theater
{
public theater()
{
//this.session = new HashSet<session>();
}
[Key]
public int idTheater { get; set; }
public string name { get; set; }
public string address { get; set; }
public int idLocality { get; set; }
public double latitude { get; set; }
public double longitude { get; set; }
public int seats { get; set; }
public string phone { get; set; }
public string email { get; set; }
public bool threeD { get; set; }
[ForeignKey("idLocality")]
public virtual locality locality { get; set; }
//public ICollection<session> session { get; set; }
}