C# - Entity Framework Code first, lazy loading not working - c#

I have some issues with Entity Framework 6 code-first with a SQL Server database.
I have an existing database, and I want to use them with Entity Framework. With Visual Studio 2017, I add a new item of type ADO.NET Entity Data Model to generate the code-first classes for the first time.
Once the classes are generated, I start to use the objects to interact with the database. Here I have some issues with lazy loading. Some navigation properties are null. The navigation properties are marked with virtual and lazy loading and ProxyCreationEnabled are true.
These screenshots illustrate the problem:
I can share the classes generated by Visual Studio:
public partial class ETRFContext : DbContext
{
static string conn = "My connection string";
public ETRFContext() : base(conn)
{
}
public virtual DbSet<Acessos> Acessos { get; set; }
public virtual DbSet<Caracteristicas> Caracteristicas { get; set; }
public virtual DbSet<CircuitoAprovacoes> CircuitoAprovacoes { get; set; }
public virtual DbSet<EstadosEstudo> EstadosEstudo { get; set; }
public virtual DbSet<Estudos> Estudos { get; set; }
public virtual DbSet<GruposAcesso> GruposAcesso { get; set; }
public virtual DbSet<HistoricoDetalhadoEstudo> HistoricoDetalhadoEstudo { get; set; }
public virtual DbSet<MembrosGruposAcesso> MembrosGruposAcesso { get; set; }
public virtual DbSet<Normas> Normas { get; set; }
public virtual DbSet<Paises> Paises { get; set; }
public virtual DbSet<PrecedenciasEstudos> PrecedenciasEstudos { get; set; }
public virtual DbSet<PrecedenciasProgramas> PrecedenciasProgramas { get; set; }
public virtual DbSet<Programas> Programas { get; set; }
public virtual DbSet<Projetos> Projetos { get; set; }
public virtual DbSet<RegistosCAD> RegistosCAD { get; set; }
public virtual DbSet<TiposEstadoEstudo> TiposEstadoEstudo { get; set; }
public virtual DbSet<TiposMensagem> TiposMensagem { get; set; }
public virtual DbSet<TiposProjeto> TiposProjeto { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Caracteristicas>()
.Property(e => e.Chave)
.IsFixedLength();
modelBuilder.Entity<Caracteristicas>()
.Property(e => e.Valor)
.IsFixedLength();
modelBuilder.Entity<Estudos>()
.HasMany(e => e.EstadosEstudo)
.WithRequired(e => e.Estudos)
.HasForeignKey(e => e.idEstudo);
modelBuilder.Entity<Estudos>()
.HasMany(e => e.HistoricoDetalhadoEstudo)
.WithRequired(e => e.Estudos)
.HasForeignKey(e => e.idEstudo);
modelBuilder.Entity<Estudos>()
.HasMany(e => e.PrecedenciasEstudos)
.WithRequired(e => e.Estudos)
.HasForeignKey(e => e.idEstudo);
modelBuilder.Entity<Estudos>()
.HasMany(e => e.PrecedenciasEstudos1)
.WithRequired(e => e.Estudos1)
.HasForeignKey(e => e.idEstudoPrecedencia)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Estudos>()
.HasMany(e => e.RegistosCAD)
.WithRequired(e => e.Estudos)
.HasForeignKey(e => e.idEstudo);
modelBuilder.Entity<GruposAcesso>()
.HasMany(e => e.Acessos)
.WithRequired(e => e.GruposAcesso)
.HasForeignKey(e => e.idGruposAcesso);
modelBuilder.Entity<GruposAcesso>()
.HasMany(e => e.MembrosGruposAcesso)
.WithRequired(e => e.GruposAcesso)
.HasForeignKey(e => e.idGrupoAcesso);
modelBuilder.Entity<Paises>()
.HasMany(e => e.Projetos)
.WithOptional(e => e.Paises)
.HasForeignKey(e => e.id_Pais);
modelBuilder.Entity<Programas>()
.HasMany(e => e.Acessos)
.WithRequired(e => e.Programas)
.HasForeignKey(e => e.idPrograma);
modelBuilder.Entity<Programas>()
.HasMany(e => e.CircuitoAprovacoes)
.WithRequired(e => e.Programas)
.HasForeignKey(e => e.idPrograma);
modelBuilder.Entity<Programas>()
.HasMany(e => e.Estudos)
.WithRequired(e => e.Programas)
.HasForeignKey(e => e.idProgramas);
modelBuilder.Entity<Programas>()
.HasMany(e => e.PrecedenciasProgramas)
.WithRequired(e => e.Programas)
.HasForeignKey(e => e.idProgramaPrecedencia);
modelBuilder.Entity<Programas>()
.HasMany(e => e.PrecedenciasProgramas1)
.WithRequired(e => e.Programas1)
.HasForeignKey(e => e.idPrograma)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Projetos>()
.HasMany(e => e.Caracteristicas)
.WithRequired(e => e.Projetos)
.HasForeignKey(e => e.id_projeto);
modelBuilder.Entity<Projetos>()
.HasMany(e => e.Estudos)
.WithRequired(e => e.Projetos)
.HasForeignKey(e => e.idProjetos);
modelBuilder.Entity<TiposEstadoEstudo>()
.HasMany(e => e.EstadosEstudo)
.WithRequired(e => e.TiposEstadoEstudo)
.HasForeignKey(e => e.idEstado);
modelBuilder.Entity<TiposMensagem>()
.HasMany(e => e.HistoricoDetalhadoEstudo)
.WithRequired(e => e.TiposMensagem)
.HasForeignKey(e => e.idTipoMensagem);
modelBuilder.Entity<TiposProjeto>()
.HasMany(e => e.Programas)
.WithRequired(e => e.TiposProjeto)
.HasForeignKey(e => e.idTiposProjeto);
modelBuilder.Entity<TiposProjeto>()
.HasMany(e => e.Projetos)
.WithRequired(e => e.TiposProjeto)
.HasForeignKey(e => e.id_Tipo)
.WillCascadeOnDelete(false);
}
}
Now this is the class Estudos:
public partial class Estudos
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Estudos()
{
EstadosEstudo = new HashSet<EstadosEstudo>();
HistoricoDetalhadoEstudo = new HashSet<HistoricoDetalhadoEstudo>();
PrecedenciasEstudos = new HashSet<PrecedenciasEstudos>();
PrecedenciasEstudos1 = new HashSet<PrecedenciasEstudos>();
RegistosCAD = new HashSet<RegistosCAD>();
}
public int id { get; set; }
public int idProjetos { get; set; }
public int idProgramas { get; set; }
[Required]
[StringLength(25)]
public string NomeEstudo { get; set; }
[Required]
[StringLength(5)]
public string Utilizador { get; set; }
public DateTime DataInicial { get; set; }
public DateTime? DataFinal { get; set; }
public bool Producao { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<EstadosEstudo> EstadosEstudo { get; set; }
public virtual Programas Programas { get; set; }
public virtual Projetos Projetos { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<HistoricoDetalhadoEstudo> HistoricoDetalhadoEstudo { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<PrecedenciasEstudos> PrecedenciasEstudos { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<PrecedenciasEstudos> PrecedenciasEstudos1 { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<RegistosCAD> RegistosCAD { get; set; }
}
And the class Projetos:
public partial class Projetos
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Projetos()
{
Caracteristicas = new HashSet<Caracteristicas>();
Estudos = new HashSet<Estudos>();
}
public int id { get; set; }
[Required]
[StringLength(15)]
public string projeto { get; set; }
public int id_Tipo { get; set; }
[StringLength(50)]
public string Cliente { get; set; }
[StringLength(50)]
public string Designacao { get; set; }
public int? id_Pais { get; set; }
public int? CalculoEletrico { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Caracteristicas> Caracteristicas { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Estudos> Estudos { get; set; }
public virtual Paises Paises { get; set; }
public virtual TiposProjeto TiposProjeto { get; set; }
}
One thing that I noticed, is when I query the Database for a "Estudo" I don't get the navigation property "Projetos", but when I ask the database for a "Projeto" I get the navigation property "Estudos".
Another thing is that when I query the database for a "Estudo" I don't get the navigation property "Projetos", but if then I query the database for a "Projeto" where id = Estudo.idProjetos, the navigation property "Projetos" in "Estudos" that was null before, automatically fills up with the value of associated "Projeto".
So, anyone have some tips to solve this issue?
Appreciate your help.

In your Estudos entity, can you add ForeignKey attribute to Programas and Projetos properties.
[ForeignKey("idProgramas")]
public virtual Programas Programas { get; set; }
[ForeignKey("idProjetos")]
public virtual Projetos Projetos { get; set; }
And when querying Estudos include Programas and Projetos.
db.Estudos
.Include(x => x.Programas)
.Include(x => x.Projetos)
.ToList();

Related

Entity Framework Core 7.0 with postgresql [duplicate]

I have an order entity, inside it contains several entities Customer, Store and others, but Entity Framework does not fill those entities. I thought the relationships were wrong but I can't find why the entity framework does not map the entities within orders.
Orders and Customers entities:
public partial class Orders
{
public Orders()
{
OrderItems = new HashSet<OrderItems>();
}
public int OrderId { get; set; }
public int? CustomerId { get; set; }
public byte OrderStatus { get; set; }
public DateTime OrderDate { get; set; }
public DateTime RequiredDate { get; set; }
public DateTime? ShippedDate { get; set; }
public int StoreId { get; set; }
public int StaffId { get; set; }
public virtual Customers Customer { get; set; }
public virtual Staffs Staff { get; set; }
public virtual Stores Store { get; set; }
public virtual ICollection<OrderItems> OrderItems { get; set; }
}
public partial class Customers
{
public Customers()
{
Orders = new HashSet<Orders>();
}
public int CustomerId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public virtual ICollection<Orders> Orders { get; set; }
}
Entity Framework code fragment:
modelBuilder.Entity<Orders>(entity =>
{
entity.HasKey(e => e.OrderId)
.HasName("PK__orders__46596229F9C56686");
entity.ToTable("orders", "sales");
entity.Property(e => e.OrderId).HasColumnName("order_id");
entity.Property(e => e.CustomerId).HasColumnName("customer_id");
entity.Property(e => e.OrderDate)
.HasColumnName("order_date")
.HasColumnType("date");
entity.Property(e => e.OrderStatus).HasColumnName("order_status");
entity.Property(e => e.RequiredDate)
.HasColumnName("required_date")
.HasColumnType("date");
entity.Property(e => e.ShippedDate)
.HasColumnName("shipped_date")
.HasColumnType("date");
entity.Property(e => e.StaffId).HasColumnName("staff_id");
entity.Property(e => e.StoreId).HasColumnName("store_id");
entity.HasOne(d => d.Customer)
.WithMany(p => p.Orders)
.HasForeignKey(d => d.CustomerId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("FK__orders__customer__0F4872E8");
entity.HasOne(d => d.Staff)
.WithMany(p => p.Orders)
.HasForeignKey(d => d.StaffId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK__orders__staff_id__1130BB5A");
entity.HasOne(d => d.Store)
.WithMany(p => p.Orders)
.HasForeignKey(d => d.StoreId)
.HasConstraintName("FK__orders__store_id__103C9721");
});
Controller code:
Response in Postman:
One of the options is to eager load them via Include:
return await _context.Orders
.Include(o => o.Customer)
.Include(o => o.Staff)
.Include(o => o.Store)
.ToListAsync()
For more info and options please check out the "Loading Related Data" doc.

Why does the entity framework not map the customer entity in my order?

I have an order entity, inside it contains several entities Customer, Store and others, but Entity Framework does not fill those entities. I thought the relationships were wrong but I can't find why the entity framework does not map the entities within orders.
Orders and Customers entities:
public partial class Orders
{
public Orders()
{
OrderItems = new HashSet<OrderItems>();
}
public int OrderId { get; set; }
public int? CustomerId { get; set; }
public byte OrderStatus { get; set; }
public DateTime OrderDate { get; set; }
public DateTime RequiredDate { get; set; }
public DateTime? ShippedDate { get; set; }
public int StoreId { get; set; }
public int StaffId { get; set; }
public virtual Customers Customer { get; set; }
public virtual Staffs Staff { get; set; }
public virtual Stores Store { get; set; }
public virtual ICollection<OrderItems> OrderItems { get; set; }
}
public partial class Customers
{
public Customers()
{
Orders = new HashSet<Orders>();
}
public int CustomerId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public virtual ICollection<Orders> Orders { get; set; }
}
Entity Framework code fragment:
modelBuilder.Entity<Orders>(entity =>
{
entity.HasKey(e => e.OrderId)
.HasName("PK__orders__46596229F9C56686");
entity.ToTable("orders", "sales");
entity.Property(e => e.OrderId).HasColumnName("order_id");
entity.Property(e => e.CustomerId).HasColumnName("customer_id");
entity.Property(e => e.OrderDate)
.HasColumnName("order_date")
.HasColumnType("date");
entity.Property(e => e.OrderStatus).HasColumnName("order_status");
entity.Property(e => e.RequiredDate)
.HasColumnName("required_date")
.HasColumnType("date");
entity.Property(e => e.ShippedDate)
.HasColumnName("shipped_date")
.HasColumnType("date");
entity.Property(e => e.StaffId).HasColumnName("staff_id");
entity.Property(e => e.StoreId).HasColumnName("store_id");
entity.HasOne(d => d.Customer)
.WithMany(p => p.Orders)
.HasForeignKey(d => d.CustomerId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("FK__orders__customer__0F4872E8");
entity.HasOne(d => d.Staff)
.WithMany(p => p.Orders)
.HasForeignKey(d => d.StaffId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK__orders__staff_id__1130BB5A");
entity.HasOne(d => d.Store)
.WithMany(p => p.Orders)
.HasForeignKey(d => d.StoreId)
.HasConstraintName("FK__orders__store_id__103C9721");
});
Controller code:
Response in Postman:
One of the options is to eager load them via Include:
return await _context.Orders
.Include(o => o.Customer)
.Include(o => o.Staff)
.Include(o => o.Store)
.ToListAsync()
For more info and options please check out the "Loading Related Data" doc.

Asp.NET MVC & Entity Framework - Error when generating Controller using EntityFramework

I'm trying to add a controller in my ASP.NET MVC project.
I am using Entity Framework Code First (6.0), and when I right-click the Controllers folder in my project and selecting Add Controller with views using Entity Framework
And I am getting this error:
This is my RequetesContext class :
public class RequetesContext : IdentityDbContext<Utilisateur>
{
public RequetesContext ()
: base()
{
}
public DbSet<Agriculteur> Agriculteurs { get; set; }
public DbSet<DirectionRegionnale> DirectionsRegionnales { get; set; }
public DbSet<Region> Regions { get; set; }
public DbSet<EtatAvancement> EtatAvancements { get; set; }
public DbSet<TypeDeRequete> TypesDeRequetes { get; set; }
public DbSet<DirectionDesMetiers> DirectionsDesMetiers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<DirectionDesMetiers>()
.HasMany(e => e.Agriculteur)
.WithRequired(e => e.DirectionDesMetiers)
.HasForeignKey(e => e.IdDirectionDesMetiers)
.WillCascadeOnDelete(false);
modelBuilder.Entity<DirectionDesMetiers>()
.HasMany(e => e.DirectionRegionnale)
.WithRequired(e => e.DirectionDesMetiers)
.HasForeignKey(e => e.IdDirectionDesMetiers)
.WillCascadeOnDelete(false);
modelBuilder.Entity<EtatAvancement>()
.HasMany(e => e.Agriculteur)
.WithRequired(e => e.EtatAvancement)
.HasForeignKey(e => e.IdEtat)
.WillCascadeOnDelete(false);
modelBuilder.Entity<EtatAvancement>()
.HasMany(e => e.DirectionRegionnale)
.WithRequired(e => e.EtatAvancement)
.HasForeignKey(e => e.IdEtat)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Region>()
.HasMany(e => e.Agriculteur)
.WithRequired(e => e.Region)
.HasForeignKey(e => e.IdRegion)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Region>()
.HasMany(e => e.DirectionRegionnale)
.WithRequired(e => e.Region)
.HasForeignKey(e => e.IdRegion)
.WillCascadeOnDelete(false);
modelBuilder.Entity<TypeDeRequete>()
.HasMany(e => e.Agriculteur)
.WithRequired(e => e.TypeDeRequete)
.HasForeignKey(e => e.IdTypeDeRequete)
.WillCascadeOnDelete(false);
modelBuilder.Entity<TypeDeRequete>()
.HasMany(e => e.DirectionRegionnale)
.WithRequired(e => e.TypeDeRequete)
.HasForeignKey(e => e.IdTypeDeRequete)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Utilisateur>()
.HasMany(e => e.Agriculteur)
.WithRequired(e => e.Utilisateur)
.HasForeignKey(e => e.IdUtilisateur)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Utilisateur>()
.HasMany(e => e.DirectionRegionnale)
.WithRequired(e => e.Utilisateur)
.HasForeignKey(e => e.IdUtilisateur)
.WillCascadeOnDelete(false);
}
and this is my Agriculteur model class:
public class Agriculteur
{
[Key]
public int IdAgriculteur { get; set; }
[Display(Name = "CIN")]
public string CinAgriculteur { get; set; }
[Display(Name = "Nom agriculteur")]
public string NomAgriculteur { get; set; }
[Display(Name = "Prénom agriculteur")]
public string PrenomAgriculteur { get; set; }
[Display(Name = "Type requête")]
public int IdTypeDeRequete { get; set; }
public virtual TypeDeRequete TypeDeRequete { get; set; }
[Display(Name = "Etat")]
public int IdEtat { get; set; }
public virtual EtatAvancement EtatAvancement { get; set; }
[Display(Name = "Direction des métiers")]
public int IdDirectionDesMetiers { get; set; }
public virtual DirectionDesMetiers DirectionDesMetiers { get; set; }
[Display(Name = "Région")]
public int IdRegion { get; set; }
public virtual Region Region { get; set; }
[Display(Name = "Objet requête")]
public string Objet { get; set; }
[Display(Name = "Date arrivée")]
public DateTime? DateArrivee { get; set; }
[Display(Name = "Date Cloture")]
public DateTime? DateCloture { get; set; }
public string IdUtilisateur { get; set; }
[ForeignKey("IdUtilisateur")]
public virtual Utilisateur Utilisateur { get; set; }
}
And this is my Utilisateur Class :
public class Utilisateur : IdentityUser
{
public string Nom { get; set; }
public string Prenom { get; set; }
public virtual ICollection<Agriculteur> Agriculteur { get; set; }
}
For more information I am using
Entity Framework version 6.0.0.0
Microsoft.AspNet.Identity.EntityFramework version 2.0.0.0
Microsoft.Owin version 3.0.1.0
Please Help me !

Entity Framework - Foreign Key Constraint

I have 3 tables in a database:
Song (ID, Title, ReleaseDate)
Album (ID, Title, ReleaseDate)
Artist (ID, FirstName, LastName)
I have a Related table so that song can be related to an Album or an Artist, or both:
RelatedSong (ID, ParentID, SongID, TrackNumber) (Foreign Key on Album.ID and Artist.ID for ParentID and obviously Song.ID for SongID)
So, using these four tables, I expected Entity Framework to generate models that would allow me to simply execute and run in my MVC project, but it fails upon saving due to a Foreign Key Constraint. If I set the ParentID = Album.ID, then it complains that Artist.ID is NULL, and vise-versa. Any suggestions? I am rewriting the front-end for an existing application so the database can't change. I need to know how the model needs to be constructed so that this works. It's either in the model or the modelBuilder (Fluent API).
Album Model:
[Table("Album")]
public partial class Album
{
public Album()
{
RelatedAlbums = new HashSet<RelatedAlbum>();
RelatedSongs = new HashSet<RelatedSong>();
}
public Guid ID { get; set; }
[Required]
public string Title { get; set; }
public DateTime ReleaseDate { get; set; }
public virtual ICollection<RelatedAlbum> RelatedAlbums { get; set; }
public virtual ICollection<RelatedSong> RelatedSongs { get; set; }
}
Artist Model:
[Table("Artist")]
public partial class Artist
{
public Artist()
{
RelatedAlbums = new HashSet<RelatedAlbum>();
RelatedSongs = new HashSet<RelatedSong>();
}
public Guid ID { get; set; }
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
public virtual ICollection<RelatedAlbum> RelatedAlbums { get; set; }
public virtual ICollection<RelatedSong> RelatedSongs { get; set; }
}
Related Album:
[Table("RelatedAlbum")]
public partial class RelatedAlbum
{
public Guid ID { get; set; }
public Guid ParentID { get; set; }
public Guid AlbumID { get; set; }
public virtual Album Album { get; set; }
public virtual Artist Artist { get; set; }
}
Related Song:
[Table("RelatedSong")]
public partial class RelatedSong
{
public Guid ID { get; set; }
public Guid ParentID { get; set; }
public Guid SongID { get; set; }
public int? TrackNumber { get; set; }
public virtual Album Album { get; set; }
public virtual Artist Artist { get; set; }
public virtual Song Song { get; set; }
}
Song:
[Table("Song")]
public partial class Song
{
public Song()
{
RelatedSongs = new HashSet<RelatedSong>();
}
public Guid ID { get; set; }
[Required]
public string Title { get; set; }
public DateTime ReleaseDate { get; set; }
public virtual ICollection<RelatedSong> RelatedSongs { get; set; }
}
DbContext:
public partial class MusicDbContext : DbContext
{
public MusicDbContext()
: base("name=MusicDbContext")
{
}
public virtual DbSet<Album> Albums { get; set; }
public virtual DbSet<Artist> Artists { get; set; }
public virtual DbSet<RelatedAlbum> RelatedAlbums { get; set; }
public virtual DbSet<RelatedSong> RelatedSongs { get; set; }
public virtual DbSet<Song> Songs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Album>()
.HasMany(e => e.RelatedAlbums)
.WithRequired(e => e.Album)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Album>()
.HasMany(e => e.RelatedSongs)
.WithRequired(e => e.Album)
.HasForeignKey(e => e.ParentID)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Artist>()
.HasMany(e => e.RelatedAlbums)
.WithRequired(e => e.Artist)
.HasForeignKey(e => e.ParentID)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Artist>()
.HasMany(e => e.RelatedSongs)
.WithRequired(e => e.Artist)
.HasForeignKey(e => e.ParentID)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Song>()
.HasMany(e => e.RelatedSongs)
.WithRequired(e => e.Song)
.WillCascadeOnDelete(false);
}
}
UPDATE:
Below is the controller code for the Create method.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID,ParentID,SongID,TrackNumber")] RelatedSong relatedSong)
{
if (ModelState.IsValid)
{
relatedSong.ID = Guid.NewGuid();
db.RelatedSongs.Add(relatedSong);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.ParentID = new SelectList(db.Albums, "ID", "Title", relatedSong.ParentID);
ViewBag.SongID = new SelectList(db.Songs, "ID", "Title", relatedSong.SongID);
return View(relatedSong);
}
UPDATE 2:
Maybe the database model is not correct or something? Not sure why this wouldn't be possible because it seems to me like this is the most efficient way to relate data to more than one "parent". I just read another post that says that it's not possible (but why would the database designer allow me to do this?)...
See: Multiple foreign keys to a single column
Your problem is here:
1.
modelBuilder.Entity<Album>()
.HasMany(e => e.RelatedAlbums)
.WithRequired(e => e.Album)
.WillCascadeOnDelete(false);
There should be WithOptional(e => e.Album)
2.
modelBuilder.Entity<Album>()
.HasMany(e => e.RelatedSongs)
.WithRequired(e => e.Album)
.HasForeignKey(e => e.ParentID)
.WillCascadeOnDelete(false);
There should be WithOptional(e => e.Album)
3.
modelBuilder.Entity<Artist>()
.HasMany(e => e.RelatedAlbums)
.WithRequired(e => e.Artist)
.HasForeignKey(e => e.ParentID)
.WillCascadeOnDelete(false);
There should be WithOptional(e => e.Artist)
4.
modelBuilder.Entity<Artist>()
.HasMany(e => e.RelatedSongs)
.WithRequired(e => e.Artist)
.HasForeignKey(e => e.ParentID)
.WillCascadeOnDelete(false);
There should be WithOptional(e => e.Artist)
5.
modelBuilder.Entity<Song>()
.HasMany(e => e.RelatedSongs)
.WithRequired(e => e.Song)
.WillCascadeOnDelete(false);
There should be WithOptional(e => e.Song)
You wrote that them are not required, but in configuration you set them required. And you should set foreign key properties to nullable types.
[Table("RelatedSong")]
public partial class RelatedSong
{
public Guid ID { get; set; }
public Guid? ParentID { get; set; }
...
}
[Table("RelatedAlbum")]
public partial class RelatedAlbum
{
public Guid ID { get; set; }
public Guid? ParentID { get; set; }
public Guid? AlbumID { get; set; }
...
}
and so on.
You are trying to insert a "Related Song" without an "Album" which is mandatory in
if (ModelState.IsValid)
{
relatedSong.ID = Guid.NewGuid();
db.RelatedSongs.Add(relatedSong);
db.SaveChanges();
return RedirectToAction("Index");
}
You could use something like this if you had the relation / types set up slightly differently
if (ModelState.IsValid)
{
Song song = GetSongById(originalSongId, db);
Song relatedSong = GetSongById(relatedSongId, db);
song.RelatedSongs.Add(relatedSong);
db.SaveChanges();
return RedirectToAction("Index");
}
You can have two FK in the Song table and make both as nullable, in this case you can refer a song to both without a third table, and at the same time EF would work perfectly.
Song (ID, Title, ReleaseDate, AlbumID nullable, ArtistID nullable)
Album (ID, Title, ReleaseDate)
Artist (ID, FirstName, LastName)
here the correction of your code
Song(ID,Title,ReleaseDate)
Album(ID,Title,ReleaseDate)
Artist(ID,FirstName,LastName)
RelatedSong(ID,ParentID,SongID,ArtistID,AlbumID,TrackNumber)
[Table("RelatedSong")]
public partial class RelatedSong
{
public Guid ID { get; set; }
public Guid ParentID { get; set; } // this will be used for the Parent Song
public Guid SongID { get; set; }
public Guid ArtistId {get; set;} // this will be used for artist foreign key
public Guid AlbumId {get; set;} // this will be used for album foreign key
public int? TrackNumber { get; set; }
public virtual Album Album { get; set; }
public virtual Artist Artist { get; set; }
public virtual Song Song { get; set; }
}
modelBuilder.Entity<Album>()
.HasMany(e => e.RelatedSongs)
.WithRequired(e => e.Album)
.HasForeignKey(e => e.ParentID) // here you should use AlbumId and not ParentID
.WillCascadeOnDelete(false);
modelBuilder.Entity<Artist>()
.HasMany(e => e.RelatedSongs)
.WithRequired(e => e.Artist)
.HasForeignKey(e => e.ParentID) // here you should use ArtistId and not ParentID, which you already used it in the Album above
modelBuilder.Entity<Song>()
.HasMany(e => e.RelatedSongs)
.WithRequired(e => e.Song)
.HasForeignKey(e=>e.ParentID); // here you will use the parent id for the song relation
.WillCascadeOnDelete(false);
based on this you can fix the other problems if any
hope this will help you

EF 4.1 Fluent API dB first relationship mapping problem

I have the following tables,
Product(pro_iIDX[PK], pro_sName)
Manufacturer(man_iIDX[PK], man_sName)
ProductManufacturer(pma_iIDX[PK], pma_iProductRef[FK], pma_iManufacturerRef[FK], pma_bAvailable)
I have the following POCOs,
public class ProductInfo
{
public int IDX { get; set; }
public string Name { get; set; }
public virtual ICollection<ProductManufacturerInfo> C0ProductManufacturers
{ get; set; }
}
public class ManufacturerInfo
{
public int IDX { get; set; }
public string Name { get; set; }
public virtual ICollection<ProductManufacturerInfo> C0ProductManufacturers
{ get; set; }
}
public class ProductManufacturerInfo
{
public int IDX { get; set; }
public bool Available { get; set; }
public virtual ManufacturerInfo C0Manufacturer { get; set; }
public virtual ProductInfo C0ProductInfo { get; set; }
}
I have used the following mappings without success,
public ProductManufacturerConfiguration()
{
ToTable("ProductManufacturer");
HasKey(p => p.IDX);
Property(p => p.IDX).HasColumnName("pma_iIDX");
Property(p => p.Available).HasColumnName("pma_bAvailable");
Property(p => p.ProductRef).HasColumnName("pma_iProductRef");
Property(p => p.ManufacturerRef).HasColumnName("pma_iManufacturerRef");
//I have tried
HasRequired(p => p.ManufacturerInfo)
.WithMany(c => c.C0ProductManufacturers)
.Map(m => m.MapKey("pma_iManufacturerRef"));
HasRequired(p => p.ProductInfo)
.WithMany(c => c.C0ProductManufacturers)
.Map(m => m.MapKey("pma_iProductRef"));
//As well as
HasRequired(p => p.C0Manufacturer)
.WithMany(c => c.C0ProductManufacturers)
.HasForeignKey(p => p.ManufacturerRef);
HasRequired(p => p.C0Product)
.WithMany(c => c.C0ProductManufacturers)
.HasForeignKey(p => p.C0Product);
}
From my trials, dB first complains about not finding ManufacturerInfo_IDX when I execute the following,
var query = from p in _context.Product
select p;
If I go the code first route, the following table is created,
ProductManufacturer(
pma_iIDX[PK],
pma_iProductRef,
pma_iManufacturerRef,
pma_bAvailable,
ManufacturerInfo_IDX,
ProductInfo_IDX)
Any assistance will be highly appreciated.
I hardly believe that sample you provided is your real code because it even doesn't compile. Is it so hard to copy a real code to show a problem?
This works:
public class ProductInfo
{
public int IDX { get; set; }
public string Name { get; set; }
public virtual ICollection<ProductManufacturerInfo> C0ProductManufacturers
{ get; set; }
}
public class ManufacturerInfo
{
public int IDX { get; set; }
public string Name { get; set; }
public virtual ICollection<ProductManufacturerInfo> C0ProductManufacturers
{ get; set; }
}
public class ProductManufacturerInfo
{
public int IDX { get; set; }
public bool Available { get; set; }
public int ManufacturerRef { get; set; }
public virtual ManufacturerInfo C0Manufacturer { get; set; }
public int ProductRef { get; set; }
public virtual ProductInfo C0ProductInfo { get; set; }
}
public class ProductManufacturerConfiguration : EntityTypeConfiguration<ProductManufacturerInfo>
{
public ProductManufacturerConfiguration()
{
ToTable("ProductManufacturer");
HasKey(p => p.IDX);
Property(p => p.IDX).HasColumnName("pma_iIDX");
Property(p => p.Available).HasColumnName("pma_bAvailable");
Property(p => p.ProductRef).HasColumnName("pma_iProductRef");
Property(p => p.ManufacturerRef).HasColumnName("pma_iManufacturerRef");
//I have tried
HasRequired(p => p.C0Manufacturer)
.WithMany(c => c.C0ProductManufacturers)
.Map(m => m.MapKey("pma_iManufacturerRef"));
HasRequired(p => p.C0ProductInfo)
.WithMany(c => c.C0ProductManufacturers)
.Map(m => m.MapKey("pma_iProductRef"));
//As well as
HasRequired(p => p.C0Manufacturer)
.WithMany(c => c.C0ProductManufacturers)
.HasForeignKey(p => p.ManufacturerRef);
HasRequired(p => p.C0ProductInfo)
.WithMany(c => c.C0ProductManufacturers)
.HasForeignKey(p => p.ProductRef);
}
}
The main problem is that your key for ProductManufacturerInfo should not really be IDX. IDX is more of a "payload" in your many-to-many association. One way to fix this is to specify a true key and then the mapping is easy:
public class ProductManufacturerInfo
{
public int IDX { get; set; }
public bool Available { get; set; }
public int C0ManufacturerIDX { get; set; }
public virtual ManufacturerInfo C0Manufacturer { get; set; }
public int C0ProductInfoIDX { get; set; }
public virtual ProductInfo C0ProductInfo { get; set; }
}
Then your mapping:
public class ProductManufacturerConfiguration
: EntityTypeConfiguration<ProductManufacturerInfo>
{
public ProductManufacturerConfiguration()
{
ToTable("ProductManufacturer");
HasKey(p => new { p.C0ManufacturerIDX, p.C0ProductInfoIDX });
Property(p => p.IDX)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}

Categories