Database not being auto-generated properly Entity Framework + Repos Pattern - asp.net-mvc

I've set up Entity Framework Code First with the Generic Repository Pattern.
Here are my models:
public interface IEntity {
int Key { get; set; }
}
public class Product : IEntity {
public int Key {
get {
return ID;
}
set {
ID = value;
}
}
public int ID { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public IEnumerable<Category> Category { get; set; }
}
public class Category : IEntity {
public int Key {
get {
return ID;
}
set {
ID = value;
}
}
public int ID { get; set; }
public string Name { get; set; }
public int ParentID { get; set; }
}
Here is my context that hooks into my generic repo:
public class EntitiesContext : DbContext, IDbContext {
public DbSet<Product> Products { get; set; }
public new IDbSet<T> Set<T>() where T : class {
return base.Set<T>();
}
}
As you can see Product has a IEnumerable of Category. If I were to create a database to match this is would be like so:
Product
- ID
- Name
- etc.
Category
- ID
- Name
- etc.
ProductCategories
- ProductID
- CategoryID
How come when my database is created that there is no joining table?

I'm pretty sure it is because you are defining the collection as an IEnumerable<T>. I think that Entity Framework needs at least an ICollection<T> to make the relationship. This SO post covers most of it.
So, change this:
public IEnumerable<Category> Category { get; set; }
To this:
public ICollection<Category> Category { get; set; }
Further, if you want to lazy load the collection, then also make it virtual:
public virtual ICollection<Category> Category { get; set; }

Related

MVC implementation of many to many relationships

This is done using MVC .net framework and entity framework "database first" approach. There is a many to many relationship between two tables. They are connected through third table that has combined key as id from first table and id from second table.
public class ManyToManyTable
{
[Required]
[Key, Column(Order=0)]
public int firsttableid { get; set; }
[Required]
[Key, Column(Order=1)]
public int secondtableid { get; set; }
public int something { get; set; }
[ForeignKey("firsttableid")]
public virtual FirstTable firstTable { get; set; }
[ForeignKey("secondtableid")]
public virtual SecondTable secondTable { get; set; }
}
First and Second table have some id which is primary key.
I want to create View and Controller method that enables master detail entry form for this ManyToManyTable. that would have FirstTable in Master and SecondTAble in details, and all to be saved in ManyToManyTable when button Save is pressed.
Of course, both First and Second Table have this property:
public virtual ICollection<ManyToManyTable> ManyToManyTables { get; set; }
What is the easiest way to implement cases like this one?
Thank you!
EF has a default conventions for many-to-many relationships. No need to create specific
mapping class. You have to include navigation properties in both "FirstTable" and "SecondTable" Class as shown below.
public class FirstTable
{
public FirstTable()
{
secondTableProperties = new HashSet<SecondTable>();
}
public int Id { get; set; }
public int MyProperty2 { get; set; }
public int MyProperty3 { get; set; }
public virtual ICollection<SecondTable> secondTableProperties { get; set; }
}
public class SecondTable
{
public SecondTable()
{
FirstTableProperties = new HashSet<FirstTable>();
}
public int Id { get; set; }
public int MyProperty2 { get; set; }
public int MyProperty3 { get; set; }
public virtual ICollection<FirstTable> FirstTableProperties { get; set; }
}
Remove mapping class from DBContext , only include above two classes. Build and run the application , EF will automatically create a Mapping table in SQL server. Usually the Mapping table contains only the primary keys of other two tables.
You can use Fluent API to take some control on the created mapping table
modelBuilder.Entity<FirstTable>()
.HasMany<SecondTable>(s => s.FirstTableProperties)
.WithMany(c => c.secondTableProperties)
.Map(cs =>
{
cs.MapLeftKey("FirstTableId");
cs.MapRightKey("SecondTableId");
cs.ToTable("ManyToManyTable");
});
If you want to work with a join table with additional properties, above mentioned many-to-many relationship won't work . In that case you will have to create two one-to-many relationships as shown below.
public class FirstTable
{
public int Id { get; set; }
public int MyProperty2 { get; set; }
public virtual ICollection<ManyToManyTable> manytomany { get; set; }
}
public class SecondTable
{
public int Id { get; set; }
public int MyProperty2 { get; set; }
public virtual ICollection<ManyToManyTable> manytomany { get; set; }
}
public ManyToManyTable
{
[Required]
[Key, Column(Order=0)]
public int firsttableid { get; set; }
[Required]
[Key, Column(Order=1)]
public int secondtableid { get; set; }
public int AdditionalProperty { get; set; }
public virtual FirstTable first { get; set; }
public virtual SecondTable Second { get; set; }
}

Want to join two tables on primary key, display the results in one view

IQueryable<Product> product = objContext.Set<Product>().Include(p =>
p.Categories.Name).Where(p => p.Id == 2);
As per the current view, I'm getting an error. It says add other model with their properties. i.e. to include Category model and corresponding Name property.
#model IEnumerable<>crudOneToMany.Models.Product>
using viewmodel, is it possible to join two tables?
View
Error
A specified Include path is not valid. The EntityType 'crudOneToMany.Models.Category' does not declare a navigation property with the name 'Name'.
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int CategoryId { get; set; }
public virtual Category Categories { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Product> Products { get; set; }
}
public class ProductDBContext : DbContext
{
public ProductDBContext()
: base("ProductDBContext")
{
}
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>().HasRequired(o => o.Categories).WithMany(o => o.Products).HasForeignKey(o => o.CategoryId);
base.OnModelCreating(modelBuilder);
}
}
Your problem is here:
.Include(p => p.Categories.Name)
Instead you should write .Include(p => p.Categories)
This means that in output there will be loaded Categories navigation collection to product.
Name is simple string property (is not navigation property so it should not be included)
Here is the proposed ViewModel for you.
ProductViewModel.cs
public class ProductViewModel
{
public int Id { get; set; }
[Required(ErrorMessage = "required")]
public string ProductName { get; set; }
public Category Category { get; set; }
public ICollection<Category> Categories { get; set; }
}

how to query against a many to many relation with entity framework 6

I have those 2 Models
public class BranchEmployees
{
public int ID { get; set; }
[Required, Column(Order = 0), Key]
public string ApplicationUserID { get; set; }
[Required, Column(Order = 1), Key]
public int BranchID { get; set; }
public virtual ICollection<ApplicationUser> ApplicationUser { get; set; }
public virtual ICollection<Branch> Branch { get; set; }
}
public class Branch
{
public int ID { get; set; }
public string BranchName { get; set; }
[Required]
public string ApplicationUserID { get; set; }
public ApplicationUser User { get; set; }
public virtual ICollection<BranchEmployees> BranchEmployees { get; set; }
}
public class ApplicationUser
{
//rest of the code
}
UPDATE
I have everything set up but what I want is the query that gets me the Employees whose IDs are in the branch employees table
, I'm using entity framework code first with MVC 5 , how do I do it ?
Assuming that your ApplicationUser class will have a navigational property called BranchEmployees, here is the query that gets me the Employees whose IDs are in the branch employees table
List<ApplicationUsers> employeeNames =
dbContext
.ApplicationUsers
.Where(au => au.BranchEmployees
.Count() > 0).ToList();
Also, can you provide whole model including ApplicationUser? I also wonder why you do not prefer BranchEmployees to inherit from ApplicationUser.
You don't need a class that indicates a many-to-many relation between two tables when you do code-first. The key here is to create virtual properties of those classes. Lets say you have a class Student and class Course. Students can be in many Courses and Courses can have many Students. To generate a database using these models the classes should look like this:
public class Student
{
private ICollection<Course> _courses;
public Student()
{
this._courses = new HashSet<Course>();
}
[Key]
public int Id { get; set; }
public string FullName { get; set; }
public virtual ICollection<Course> Courses
{
get { return this._courses; }
set { this._courses = value; }
}
}
And for Course:
public class Course
{
private ICollection<Student> _students;
public Course()
{
this._students = new HashSet<Student>();
}
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<Student> Students
{
get { return this._students; }
set { this._students = value; }
}
}
I hope that this can help you solve your issue.

Many to Many relationship code first

Hi I'm trying to create a database in MVC containing a list of Tv shows and Actors associated with them.
Each Tv show can have multiple Actors and an actor can appear on many tv shows. Each actor has a cast name too, for each show they appear in. Here's my models.
public class TvShow
{
public int ShowId { get; set; }
public string Name { get; set; }
public List<Actor> cast { get; set; }
}
public class Actor
{
public int ActorId { get; set; }
public string Name { get; set; }
public List<TvShow> shows { get; set; }
}
public class Cast
{
public int ShowId { get; set; }
public int ActorId { get; set; }
public string CastName { get; set; }
}
public class TvContext : DbContext
{
public DbSet<TvShow> Shows { get; set; }
public DbSet<Actor> Actors { get; set; }
}
I query the database and run the application to create the database for me, but the CastName attribute is not appearing in my linker table. Any help would be greatly appreciated.
How can EF know that you want to use entity Cast as a M:N relation table?
You have to link entity Cast from TvShow and Actor entities when you want to have there an additional property on many to many relationship. So the model can look like this:
public class TvShow
{
public int ShowId { get; set; }
public string Name { get; set; }
public List<Cast> Casts { get; set; }
}
public class Actor
{
public int ActorId { get; set; }
public string Name { get; set; }
public List<Cast> Shows { get; set; }
}
public class Cast
{
public string CastName { get; set; }
public TvShow TwShow { get; set; }
public Actor Actor { get; set; }
}
And you can get list of actors for given TvShow with following query:
twShow.Casts.Select(c => c.Actor);

Circular reference with ManyToMany relationship and automapper

Given the following Domain Entities:
public class Person {
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual ISet<PersonClub> Clubs { get; set; }
public Person() {
this.Clubs = new HashSet<PersonClub>();
}
}
public class Club {
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual ISet<PersonClub> Members { get; set; }
public Club() {
this.Persons = new HashSet<PersonClub>();
}
}
public class PersonClub {
public virtual Guid Id { get; set; }
public virtual Person Person { get; set; }
public virtual Club Club { get; set; }
}
and DTO's:
public class PersonDTO {
public Guid Id { get; set; }
public string Name { get; set; }
public ISet<ClubDTO> Clubs { get; set; }
public PersonDTO() {
this.Clubs = new HashSet<ClubDTO>();
}
}
public class ClubDTO {
public Guid Id { get; set; }
public string Name { get; set; }
public ISet<PersonDTO> Members { get; set; }
public ClubDTO() {
this.Members = new HashSet<PersonDTO>();
}
}
Is there a way to map these Domain Entities to their DTO's? The problem is that PersonDTO needs a collection of ClubDTO, not just Club, and vice versa for ClubDTO needing a collection of PersonDTO and not just Person.
This design causes an infinite loop when trying to map PersonClub -> PersonDTO and PersonClub -> ClubDTO:
Mapper.CreateMap<Person, PersonDTO>();
Mapper.CreateMap<Club, ClubDTO>();
Mapper.CreateMap<PersonClub, ClubDTO>()
.ConvertUsing(x => Mapper.Map<Club, ClubDTO>(x.Club));
Mapper.CreateMap<PersonClub, PersonDTO>()
.ConvertUsing(x => Mapper.Map<Person, PersonDTO>(x.Person));
I understand why this is happening, but am curious to how others handle this situation.
In this situation when calling Mapper.Map<Person, PersonDTO>(personEntity), it isn't necessary to load all members of all clubs that a person is a part of (The relationship doesn't need to go that deep ever). Same is true for Mapper.Map<Club, ClubDTO>(clubEntity).
Is this a design flaw? Would it be better to not have a PersonClub domain entity and just have public virtual ISet<Club> Clubs { get; set; } as the ManyToMany relationship? Although I believe this would still cause the circular reference.
Any input is appreciated.

Resources