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
Related
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();
There are two unusual relationships I am wrestling with. I have not found a way to "tell" EF how to build its model properly. I am using stripped down classes here to focus on the relationships. They don't seem to be in the usual 1-1, 1-M, M-M mold.
First
public class Parent1 {
public int Id { get; set; }
public string Description { get; set; }
public ICollection<Child> Children { get; set; }
}
public class Parent2 {
public int Id { get; set; }
public string Description { get; set; }
public ICollection<Child> Children { get; set; }
}
public class Child {
public int Id { get; set; }
public string OtherStuff { get; set; }
public int Parent1Id { get; set; }
public Parent1 Parent1 { get; set; }
public int Parent2Id { get; set; }
public Parent2 Parent2 { get; set; }
}
and my fluent API
modelBuilder.Entity<Parent1>()
.HasMany(c => c.Children)
.WithOne(d => d.Parent1)
.HasForeignKey(c => c.Parent1Id)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Parent2>()
.HasMany(c => c.Children)
.WithOne(d => d.Parent2)
.HasForeignKey(c => c.Parent2Id)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
EF doesn't seem to like cascading deletes from two directions.
Second
public class Parent {
public int Id { get; set; }
public string Description { get; set; }
public ICollection<Child> Children { get; set; }
}
public class Child {
public int Id { get; set; }
public string OtherStuff { get; set; }
public int Parent1Id { get; set; } // Think "Mail to"
public Parent Parent1 { get; set; }
public int Parent2Id { get; set; } // Think "Bill To". Same table, different purpose
public Parent Parent2 { get; set; }
}
and my fluent API
modelBuilder.Entity<Parent>()
.HasMany(c => c.Children)
.WithOne(d => d.Parent1)
.HasForeignKey(c => c.Parent1Id)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Parent>()
.HasMany(c => c.Children)
.WithOne(d => d.Parent2)
.HasForeignKey(c => c.Parent2Id)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
EF doesn't like pointing at TWO parents in the same entity either.
I have a Order < Customer model.
How do I set this up? When I try to insert a user with a null customerid, it tells me that it cannot be null.
The model is as follows:
public class Order
{
public long OrderID { get; set; }
public int CustomerID { get; set; }
public virtual Customer Customer { get; set; }
public virtual ICollection<OrderDetail> OrderDetails { get; set; }
}
public partial class Customer
{
public int CustomerID { get; set; }
}
In DbContext :
modelBuilder.Entity<Customer>()
.HasMany(e => e.Orders)
.WithRequired(e => e.Customer)
.WillCascadeOnDelete(false);
Have you tried to replace line
.WithRequired(e => e.Customer)
with
.WithOptional(e => e.Customer)
?
And I make the CustomerID property nullable: public int? CustomerID { get; set; }
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 !
I'm trying to model a simple QA application using code first for learning purposes. Users should be able to ask questions, answer questions and write comments for both questions and answers. Here is my model classes:
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public DateTime? BirthDate { get; set; }
public ICollection<Gym> Gyms { get; set; }
}
[Table("Question")]
public class Question
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int QuestionId { get; set; }
public int UserProfileId { get; set; }
[ForeignKey("UserProfileId")]
public UserProfile UserProfile { get; set; }
public string Header { get; set; }
public string Content { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime CreateDate { get; set; }
public ICollection<Answer> Answers { get; set; }
public ICollection<QuestionComment> QuestionComments { get; set; }
}
[Table("QuestionComment")]
public class QuestionComment
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int QuestionCommentId { get; set; }
public int UserProfileId { get; set; }
[ForeignKey("UserProfileId")]
public UserProfile UserProfile { get; set; }
public int QuestionId { get; set; }
[ForeignKey("QuestionId")]
public Question Question { get; set; }
[Column("Content", TypeName = "ntext")]
public string Content { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime CreateDate { get; set; }
}
[Table("Answer")]
public class Answer
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int AnswerId { get; set; }
public int UserProfileId { get; set; }
[ForeignKey("UserProfileId")]
public UserProfile UserProfile { get; set; }
public int QuestionId { get; set; }
[ForeignKey("QuestionId")]
public Question Question { get; set; }
[Column("Content", TypeName="ntext")]
public string Content { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime CreateDate { get; set; }
public IList<AnswerComment> AnswerComments { get; set; }
}
[Table("AnswerComment")]
public class AnswerComment
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int AnswerCommentId { get; set; }
public int UserProfileId { get; set; }
[ForeignKey("UserProfileId")]
public UserProfile UserProfile { get; set; }
public int AnswerId { get; set; }
[ForeignKey("AnswerId")]
public Answer Answer { get; set; }
[Column("Content", TypeName = "ntext")]
public string Content { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime CreateDate { get; set; }
}
And here is my db context class:
public class TestDbContext : DbContext
{
public TestDbContext()
: base("DefaultConnection")
{
}
public DbSet<UserProfile> UserProfiles { get; set; }
public DbSet<Question> Questions { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// After update
modelBuilder.Entity<UserProfile>()
.HasMany(p => p.Questions)
.WithRequired()
.HasForeignKey(c => c.UserProfileId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<UserProfile>()
.HasMany(p => p.Answers)
.WithRequired()
.HasForeignKey(c => c.UserProfileId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<UserProfile>()
.HasMany(p => p.AnswerComments)
.WithRequired()
.HasForeignKey(c => c.UserProfileId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<UserProfile>()
.HasMany(p => p.QuestionComments)
.WithRequired()
.HasForeignKey(c => c.UserProfileId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Question>()
.HasMany(p => p.Answers)
.WithRequired()
.HasForeignKey(c => c.QuestionId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Question>()
.HasMany(p => p.QuestionComments)
.WithRequired()
.HasForeignKey(c => c.QuestionId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Answer>()
.HasMany(p => p.AnswerComments)
.WithRequired()
.HasForeignKey(c => c.AnswerId)
.WillCascadeOnDelete(false);
// After update
}
}
I'm getting the following error when creating db using the above declarations:
Introducing FOREIGN KEY constraint 'AnswerComment_UserProfile' on table 'AnswerComment' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.\r\nCould not create constraint. See previous errors.
What do I have to do to fix this?
Thanks in advance,
Try adding this to your UserProfile entity:
public virtual ICollection<AnswerComment> AnswerComments { get; set; }
And then add this to your modelBuilder, this should get rid off the error in your question, and you will probably have to do this for QuestionComment, Question, and Answer:
modelBuilder.Entity<AnswerComment>()
.HasRequired(u => u.UserProfile)
.WithMany(a => a.AnswerComments)
.WillCascadeOnDelete(false);
You have a table A that contains a FK to another table B.
In the same time table A contains a FK to table C.
Now, both tables B and C contains FKs to table D.
If all FKs are defined as delete cascade a record in table C can be deleted twice.
This is not a logic problem, but SQL Server does not support this option.
To avoid this problem set on delete no action.