EF6 code first relationship between entities
I'm trying to create a condo data model in ASP.NET with SQL Server. I ran into the creation of the relationship of proprietario(1)
with fracao(many)
.
The Error returned is:
The INSERT statement conflicted with the FOREIGN KEY constraint " FK_dbo.Fracao_dbo.Owner_propertyoid". The conflict occurred in database "WebCond", table " dbo.Owner", column 'ProprietarioID'.
My classes:
[Table("Fracao")]
public class Fracao
{
[ScaffoldColumn(false)]
public int FracaoID { get; set; }
public int? ProprietarioID { get; set; }
public virtual Proprietario Proprietario { get; set; }
[Required]
public int CondominioID { get; set; }
public virtual Condominio Condominio { get; set; }
[Required]
public int ZonaID { get; set; }
public virtual Zona Zona { get; set; }
[Required, StringLength(4), Display(Name = "Letra")]
public string Letra { get; set; }
[Required, Display(Name = "Área")]
public decimal Area { get; set; }
[Required, Display(Name = "Permilagem")]
public decimal Permilagem { get; set; }
[Required, StringLength(4), Display(Name = "Piso")]
public string Piso { get; set; }
[Required, StringLength(10), Display(Name = "Porta")]
public string Porta { get; set; }
}
[Table("Proprietario")]
public class Proprietario
{
[ScaffoldColumn(false)]
public int ProprietarioID { get; set; }
[Required, StringLength(255), Display(Name = "Nome")]
public string Nome { get; set; }
[Required, StringLength(500), Display(Name = "Morada"), DataType(DataType.MultilineText)]
public string Morada { get; set; }
[Required, StringLength(30), Display(Name = "CPostal")]
public string CPostal { get; set; }
[Required, StringLength(100), Display(Name = "Localidade")]
public string Localidade { get; set; }
[StringLength(10), Display(Name = "Telefone")]
public string Telefone { get; set; }
[StringLength(10), Display(Name = "Telemovel")]
public string Telemovel { get; set; }
[DataType(DataType.EmailAddress), Display(Name = "Email")]
public string Email { get; set; }
[StringLength(10), Display(Name = "Contribuinte")]
public string Contribuinte { get; set; }
public virtual ICollection<Fracao> Fracoes { get; set; }
}
I tried to create the entities in the way I created others that are fine, but these are not.
It seems to me that the problem is related to cascade delete, and that I have to create the appropriate exceptions, but I don't know which ones.
2 answers
You could try with the following, code:
[Table("Fracao")]
public class Fracao
{
[ScaffoldColumn(false)]
public int FracaoID { get; set; }
public int? ProprietarioID { get; set; }
[InverseProperty("ID")]
[ForeignKey("ProprietarioID")]
public virtual Proprietario Proprietario { get; set; }
[Required]
public int CondominioID { get; set; }
public virtual Condominio Condominio { get; set; }
[Required]
public int ZonaID { get; set; }
public virtual Zona Zona { get; set; }
[Required, StringLength(4), Display(Name = "Letra")]
public string Letra { get; set; }
[Required, Display(Name = "Área")]
public decimal Area { get; set; }
[Required, Display(Name = "Permilagem")]
public decimal Permilagem { get; set; }
[Required, StringLength(4), Display(Name = "Piso")]
public string Piso { get; set; }
[Required, StringLength(10), Display(Name = "Porta")]
public string Porta { get; set; }
}
Because with [ForeignKey("ProprietarioID")]
, you tell the annotation that FK
is the one defined within it.
Update
Errata, I did not pay attention to the fact that your identifier has the same name as the foreign key, so please remove the annotation [InverseProperty("ID")]
.
Update 2
With the following code, which I replicated entirely on my machine, worked perfectly, try to do the same, as a test, as a new project:
DbContext class:
public class TesteContext : DbContext
{
public DbSet<Fracao> Fracoes { get; set; }
public DbSet<Proprietario> Proprietarios { get; set; }
}
Fraction Class:
[Table("Fracao")]
public class Fracao
{
[ScaffoldColumn(false)]
public int FracaoID { get; set; }
public int? ProprietarioID { get; set; }
[ForeignKey("ProprietarioID")]
public virtual Proprietario Proprietario { get; set; }
[StringLength(4), Display(Name = "Letra")]
public string Letra { get; set; }
[Display(Name = "Área")]
public decimal Area { get; set; }
[Display(Name = "Permilagem")]
public decimal Permilagem { get; set; }
[StringLength(4), Display(Name = "Piso")]
public string Piso { get; set; }
[StringLength(10), Display(Name = "Porta")]
public string Porta { get; set; }
}
Owner Class:
[Table("Proprietario")]
public class Proprietario
{
[ScaffoldColumn(false)]
public int ProprietarioID { get; set; }
[StringLength(255), Display(Name = "Nome")]
public string Nome { get; set; }
[StringLength(500), Display(Name = "Morada"), DataType(DataType.MultilineText)]
public string Morada { get; set; }
[StringLength(30), Display(Name = "CPostal")]
public string CPostal { get; set; }
[StringLength(100), Display(Name = "Localidade")]
public string Localidade { get; set; }
[StringLength(10), Display(Name = "Telefone")]
public string Telefone { get; set; }
[StringLength(10), Display(Name = "Telemovel")]
public string Telemovel { get; set; }
[DataType(DataType.EmailAddress), Display(Name = "Email")]
public string Email { get; set; }
[StringLength(10), Display(Name = "Contribuinte")]
public string Contribuinte { get; set; }
public virtual ICollection<Fracao> Fracoes { get; set; }
}
And the codes of a console program:
using (var db = new TesteContext())
{
// Create and save a new Blog
Console.Write("Enter a name for a new Blog: ");
var name = Console.ReadLine();
var proprietario = new Proprietario { Email = "oi" };
proprietario = db.Proprietarios.Add(proprietario);
db.SaveChanges();
var fracao = new Fracao { Area = 1, Proprietario = proprietario };
db.Fracoes.Add(fracao);
db.SaveChanges();
// Display all Blogs from the database
var query = from b in db.Fracoes
orderby b.Area
select b;
Console.WriteLine("All blogs in the database:");
foreach (var item in query)
{
Console.WriteLine(item.Area);
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
With this code, you can enter a fraction and an owner, doing the binding correctly, if you want to do the update, you will have to do the following:
var fracao = new Fracao { Area = 1, Proprietario = null, ProprietarioId = proprietario.ProprietarioId };
Try again with these codes and comment if you achieve.
In class Proprietario
, put a constructor that initializes ICollection<Fracoes>
. For example:
public class Proprietario {
public Proprietario( ) {
Fracoes = new List<Fracao>( );
}
...
public virtual ICollection<Fracao> Fracoes { get; set; }
}
Thus correctly configures the One-To-Many
relationship between the models. There is an article here in English that explains as well.
Update
I created my own Code-first and copied their classes the way they are, with my modification (I didn't include Zona
or Condominio
only). In the end, I had a class like this:
Fracao
[Table( "Fracao" )]
public class Fracao
{
[ScaffoldColumn( false )]
public int FracaoID { get; set; }
public int? ProprietarioID { get; set; }
public virtual Proprietario Proprietario { get; set; }
[Required, StringLength( 4 ), Display( Name = "Letra" )]
public string Letra { get; set; }
[Required, Display( Name = "Área" )]
public decimal Area { get; set; }
[Required, Display( Name = "Permilagem" )]
public decimal Permilagem { get; set; }
[Required, StringLength( 4 ), Display( Name = "Piso" )]
public string Piso { get; set; }
[Required, StringLength( 10 ), Display( Name = "Porta" )]
public string Porta { get; set; }
}
owner
[Table( "Proprietario" )]
public class Proprietario
{
public Proprietario( )
{
Fracoes = new List<Fracao>( );
}
[ScaffoldColumn( false )]
public int ProprietarioID { get; set; }
[Required, StringLength( 255 ), Display( Name = "Nome" )]
public string Nome { get; set; }
[Required, StringLength( 500 ), Display( Name = "Morada" ), DataType( DataType.MultilineText )]
public string Morada { get; set; }
[Required, StringLength( 30 ), Display( Name = "CPostal" )]
public string CPostal { get; set; }
[Required, StringLength( 100 ), Display( Name = "Localidade" )]
public string Localidade { get; set; }
[StringLength( 10 ), Display( Name = "Telefone" )]
public string Telefone { get; set; }
[StringLength( 10 ), Display( Name = "Telemovel" )]
public string Telemovel { get; set; }
[DataType( DataType.EmailAddress ), Display( Name = "Email" )]
public string Email { get; set; }
[StringLength( 10 ), Display( Name = "Contribuinte" )]
public string Contribuinte { get; set; }
public virtual ICollection<Fracao> Fracoes { get; set; }
}
And I ended up with tables and columns like this: