Querying Many to Many relationship table to entities MVC - model-view-controller

I have many to many relationship tables. Sube and User
namespace Odev.Entities
{
public class User
{
[Key]
public int Id { get; set; }
[Required]
[DisplayName("Kimlik No")]
[ StringLength(11)]
[Index(IsUnique = true)]
public string UserName { get; set; }
[ StringLength(8)]
[DisplayName("Şifre")]
public string Password { get; set; }
[DisplayName("Ad Soyad")]
public string NameSurname { get; set; }
[DisplayName("Bölüm")]
public string Bolum { get; set; }
[DisplayName("Dal")]
public string Dal { get; set; }
[DisplayName("Öğrenci No")]
public int OgrenciNo { get; set; }
public int RoleId { get; set; }
public virtual ICollection<Sube> Subes { get; set; }
public virtual List<Notification> Notifications { get; set; }
public virtual List<Homework> Homeworks { get; set; }
public virtual Role Role { get; set; }
}
}
namespace Odev.Entities
{
public class Sube
{
[Key]
public int Id { get; set; }
[DisplayName("Şube")]
public string Sube_Name { get; set; }
public virtual Homework Homework { get; set; }
public virtual ICollection<User> Users { get; set; }
}
}
namespace Odev.DataAccessLayer
{
public class DatabaseContext : DbContext
{
public DatabaseContext() : base("dataConnection")
{
Database.SetInitializer(new OdevInitializer());
}
public DbSet<User> Users { get; set; }
public DbSet<Homework> Homeworks { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<Sube> Subes { get; set; }
public DbSet<Notification> Notifications { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
}
and my ViewModel
namespace Odev.Models{
public class ViewModel{
public string Sube_Name { get; set; }
public string NameSurname { get; set; }
public string UserName { get; set; }
public int UserId { get; set; }
public int SubeId { get; set; }
public User User { get; set; }
public Sube Sube { get; set; }
public Role Role { get; set; }
}}
I want to show User's SubeId:
How I select Sube's id ?

You need connect both entities with a foreign key.
Please, read this doc: Creating a More Complex Data Model for an ASP.NET MVC Application

Related

How do I define this relationship with code-first?

I'm trying to create a library of books.
I separated data and users context/database for security reasons (and clarity) but is it that useful?
Specially since BookOfUserEntity.Id should be really a composite key between UserId & BookId.
Something like :
public class BookOfUserEntity
{
[Key]
public Guid UserId { get; set; }
[Key]
public int BookId { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BookOfUserEntity>()
.HasKey(b => new { b.UserId, b.BookId });
}
But then if I create a composite key what should be HistoryEntity.BookOfUserEntityId type & value?
I also separated BookEntity & BookOfUserEntity to avoid duplicated data and reuse what can be reused (MainCoverArtId etc...), but this added complexity - should I go back to a simpler model?
public class BookEntity
{
public int Id { get; set; }
public Guid? MainCoverArtId { get; set; }
...
public virtual List<BookOfUserEntity>? BookOfUserEntities { get; set; } // Only purpose is to know how many Users have this very book in their list.
}
public class BookOfUserEntity // Bad name here don't mention it
{
public int Id { get; set; }
public Guid UserId { get; set; }
public int BookId { get; set; }
public BookEntity Book { get; set; } // Useful? Should be virtual?
public List<HistoryEntity>? HistoryEntities { get; set; }
...
}
public class HistoryEntity
{
public int Id { get; set; }
public int BookOfUserEntityId { get; set; }
public BookOfUserEntity BookOfUserEntity { get; set; } // Same questions
public int Vol { get; set; }
public double Chapter { get; set; }
public DateTime? ReadDate { get; init; }
}

Why is Entity Framework navigation property null?

I am use code first model with a relationship below
public class ApplicationUser : IdentityUser
{
public string UserFirstName { get; set; }
public string UserLastName { get; set; }
public string UserSchool { get; set; }
public UserProfileData UserProfileData { get; set; }
public int? MedicalSpecialtyId { get; set; }
public virtual MedicalSpecialty MedicalSpecialty { get; set; }
// public int? AnalyticsDataId { get; set; }
// public ICollection<AnalyticsData> AnalyticsDatas { get; set; }
}
public class MedicalSpecialty
{
public int Id { get; set; }
public string Description { get; set; }
// public int ApplicationUserId { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
public ICollection<ProgramDetailData> ProgramDetailDatas { get; set; }
}
And when I try to get a User's associated MedicalSpecialty object it is NULL
userSpecialtyName = currentUser.MedicalSpecialty.Description;
BUT when I run this code above it the currentUser.MedicalSpecialty is no longer NULL. What happened?? Somehow that LINQ query woke up the object and filled it with data
var userSpecialtyId = currentUser.MedicalSpecialtyId;
userSpecialtyName = _medicalSpecialtyRepository.Find
(x => x.Id == userSpecialtyId).FirstOrDefault().Description;
userSpecialtyName = currentUser.MedicalSpecialty.Description;

Entity Framework not binding entity

I have the following db structure:
I am using EF6 to create the entities from database and have the following classes created by EF6:
public partial class Mechanic
{
public Mechanic()
{
this.MechanicAddresses = new HashSet<MechanicAddress>();
this.MechanicServices = new HashSet<MechanicService>();
}
public string ID { get; set; }
public string Email { get; set; }
public bool EmailConfirmed { get; set; }
public string PasswordHash { get; set; }
public string SecurityStamp { get; set; }
public string PhoneNumber { get; set; }
public bool PhoneNumberConfirmed { get; set; }
public bool TwoFactorEnabled { get; set; }
public Nullable<System.DateTime> LockoutEndDateUtc { get; set; }
public bool LockoutEnabled { get; set; }
public int AccessFailedCount { get; set; }
public string UserName { get; set; }
public string CompanyName { get; set; }
public string ContactName { get; set; }
public string MobileNumber { get; set; }
public Nullable<bool> IsMobile { get; set; }
public string Url { get; set; }
public string FaceBookUrl { get; set; }
public string TwitterUrl { get; set; }
public string Description { get; set; }
public string Discriminator { get; set; }
public bool IsEnabled { get; set; }
public bool IsAuthorised { get; set; }
public string Logo { get; set; }
public System.DateTime CreationTimestamp { get; set; }
public virtual ICollection<MechanicAddress> MechanicAddresses { get; set; }
public virtual ICollection<MechanicService> MechanicServices { get; set; }
}
public partial class MechanicAddress
{
public int ID { get; set; }
public string MechanicId { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string AddressLine3 { get; set; }
public string District { get; set; }
public string Region { get; set; }
public string PostalCode { get; set; }
public int CountryId { get; set; }
public System.DateTime CreationTimestamp { get; set; }
public bool IsPrimary { get; set; }
public Nullable<double> Latitude { get; set; }
public Nullable<double> Longitude { get; set; }
public System.Data.Entity.Spatial.DbGeography Location { get; set; }
public virtual Country Country { get; set; }
public virtual Mechanic Mechanic { get; set; }
}
public partial class MechanicService
{
public int ID { get; set; }
public string MechanicId { get; set; }
public string Service { get; set; }
public virtual Mechanic Mechanic { get; set; }
}
The data is correct so i expect to get data in all entities.
When i run the following linq query in my DAL:
Mechanic mech = context.Mechanics.Where(a => a.ID == id).Include(a => a.MechanicAddresses).Include(a => a.MechanicServices).FirstOrDefault();
It returns the mechanic and mechanicAddresses but mechanicServices is always empty (count == 0).
When i run the same query in LinqPad I get all entities filled as expected.
I have removed the edmx and re-created it but still get the same issue.
Please check if "MultipleActiveResultSets" is set to true and LazyLoadingEnabled is enabled in connection string. It may help.
And what about your OnModelCreating?
protected override void OnModelCreating(DbModelBuilder modelBuilder)
It's not necessary to use Include if you have LazyLoading (virtual). And If it works fine in LinqPad try to do migration into empty DB (just test). And then try to get data from test DB.
The only way i was able to resolve this was to:
delete the EDMX
script the create for the mechanicsServices table
script the data
drop the mechanicsServices table
run the create table script from above
run the insert data script
regenerate the EDMX
This now works, WTF! Can't explain it.
I know it's always best to understand what went wrong but this one beat me.
I had same problem.
If you using git, please check .edmx file old version. SSDL content may be missing.

Entity Framework also Linq advice needed

i have got on my DB 3 tables
movies, workers, workermovies ( this is the Relationship table )
public class Movie
{
public Movie()
{
Genres = new List<Genre>();
Formats = new List<Format>();
ProductionCompanies = new List<ProductionCompany>();
Workers = new List<Worker>();
}
public int Id { get; set; }
public string Title { get; set; }
public DateTime ReleaseDate { get; set; }
public string StoryLine { get; set; }
public int RunTime { get; set; }
[ForeignKey("MPAARateId")]
public MPAARate MPAARate { get; set; }
public int MPAARateId { get; set; }
public byte[] ImageData { get; set; }
public string ImageMimeType { get; set; }
public DateTime CreatedDate { get; set; }
public string OfficialSite { get; set; }
public int Budget { get; set; }
public int StatusId { get; set; }
public virtual ICollection<Genre> Genres { get; set; }
public virtual ICollection<Format> Formats { get; set; }
public virtual ICollection<ProductionCompany> ProductionCompanies { get; set; }
public virtual ICollection<Worker> Workers { get; set; }
}
public class Worker
{
public int Id { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public DateTime Birthday { get; set; }
public string Biography { get; set; }
public string BornName { get; set; }
public double Height { get; set; }
public DateTime? Died { get; set; }
public byte[] ImageData { get; set; }
public string ImageMimeType { get; set; }
public bool IsActor { get; set; }
public bool IsDirector { get; set; }
public bool IsWriter { get; set; }
public bool IsProducer { get; set; }
public bool IsStar { get; set; }
public virtual ICollection<Movie> Movies { get; set; }
}
in this Relation i got the movieId and the workerId
but i also got some more fields if the person acted or writen or producer etc.
how do i define the relation entity class if needed
and when i want to get just the ppl that acted in the movie how do i wrote such a linq
query
You need to introduce an additional entity in your model WorkerMovie and convert the many-to-many relationship between Worker and Movie into two one-to-many relationships - one between Worker and WorkerMovie and the other between Movie and WorkerMovie. A sketch:
public class WorkerMovie
{
[Key, Column(Order = 0)]
public int WorkerId { get; set; }
[Key, Column(Order = 1)]
public int MovieId { get; set; }
public Worker Worker { get; set; }
public Movie Movie { get; set; }
public bool WorkedAsActor { get; set; }
public bool WorkedAsWriter { get; set; }
public bool WorkedAsProducer { get; set; }
// etc.
}
public class Movie
{
// ...
public virtual ICollection<WorkerMovie> WorkerMovies { get; set; }
// remove ICollection<Worker> Workers
}
public class Worker
{
// ...
public virtual ICollection<WorkerMovie> WorkerMovies { get; set; }
// remove ICollection<Movie> Movies
}
If you want only to find the workers who were actors in a particular movie with a movieId you can write:
var workersAsActors = context.WorkerMovies
.Where(wm => wm.MovieId == movieId && wm.WorkedAsActor)
.Select(wm => wm.Worker)
.ToList();
Here is another answer to a very similar question with many more examples of possible queries: Create code first, many to many, with additional fields in association table

Entity Framework multiple relationships between tables

I've have two tables in my project which are User and InvoiceLine.
It has been specified that an InvoiceLine can have a User known as a Checker.
My models are:
public class InvoiceLine : IEntity
{
public virtual int Id { get; set; }
public virtual int? CheckerId { get; set; }
public virtual string CreatedByUserName { get; set; }
public virtual DateTime CreatedDateTime { get; set; }
public virtual string LastModifiedByUserName { get; set; }
public virtual DateTime? LastModifiedDateTime { get; set; }
// Navigation properties
public virtual User Checker{ get; set; }
}
public class User : IEntity
{
public int Id { get; set; }
public string CreatedByUserName { get; set; }
public DateTime CreatedDateTime { get; set; }
public string LastModifiedByUserName { get; set; }
public DateTime? LastModifiedDateTime { get; set; }
//Navigation properties
public virtual ICollection<InvoiceLine> InvoiceLines { get; set; }
}
So this was fine I have a 0..1 to many relationship from User to InvoiceLine.
This meant with Linq I could get the InvoiceLines the User needs to check via:
user.InvoiceLines
However there is another requirement that an InvoiceLine also has an Auditor so I modified the InvoiceLine to:
public class InvoiceLine : IEntity
{
public virtual int Id { get; set; }
public virtual int? CheckerId { get; set; }
public virtual int? AuditorId { get; set; }
public virtual string CreatedByUserName { get; set; }
public virtual DateTime CreatedDateTime { get; set; }
public virtual string LastModifiedByUserName { get; set; }
public virtual DateTime? LastModifiedDateTime { get; set; }
// Navigation properties}
public virtual User Checker { get; set; }
public virtual User Auditor { get; set; }
}
So what I was really wanting was to go:
user.InvoiceLines
and get the Checkers and Auditors or alternatively get them seperately via:
user.CheckerInvoiceLines
user.AuditorInvoiceLines
I'm getting null back from user.InvoiceLines though which is understandable.
Could someone please point me in the right direction on how to use Linq to get the InvoiceLines from the User?
Edit Update:
My model configuration code is like:
public class VectorCheckContext : DbContext
{
...
public DbSet<InvoiceLine> InvoiceLines { get; set; }
public DbSet<User> Users { get; set; }
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
}
}
You need to use fluent mappings to configure the relationships when EF can not resolve them by conventions.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
//other mappings
modelBuilder.Entity<InvoiceLine>()
.HasOptional(i => i.Checker)
.WithMany(u => u.CheckerInvoiceLines)
.HasForeignKey(i => i.CheckerId);
modelBuilder.Entity<InvoiceLine>()
.HasOptional(i => i.Auditor)
.WithMany(u => u.AuditorInvoiceLines)
.HasForeignKey(i => i.AuditorId);
}

Resources