0

I'm having some serious issues trying to create a table using code first. So this is what I have:

public class Pessoa
{
    [Key]
    public int PessoaId { get; set; }
    public virtual Empresa Empresa { get; set; }
    ...
}


public class Empresa
{
    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public int EmpresaId { get; set; }
    public virtual List<FuncionarioFree> FuncionarioFree { get; set; }
    public virtual List<FuncionarioPagante> FuncionarioPagante { get; set; }
    [Key,ForeignKey("Pessoa")]
    public int PessoaId { get; set; }
    [Required]
    public virtual Pessoa Pessoa { get; set; }
    ...
}

public class FuncionarioPagante
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int FuncionarioPaganteId { get; set; }
    public int PessoaId { get; set; }
    [ForeignKey("PessoaId")]
    public virtual Pessoa Pessoa { get; set; }
    public int EmpresaId { get; set; }
    [ForeignKey("EmpresaId")]
    public virtual Empresa Empresa { get; set; }
}

Now for what I need:

Pessoa may or may not have a Empresa(company). And Empresa has a list of FuncionarioPagante(employees).

Now when i try to insert a new FuncionarioPagante:

 var novoFuncionario = new FuncionarioPagante()
 {
        EmpresaId = empresaId,
        Pessoa = pessoaUnidade.Pessoa,
        PessoaId = pessoaUnidade.PessoaId
 };

 _contexto.FuncionarioPagante.Add(novoFuncionario);
 _contexto.SaveChanges();

It is trowing this error: (Note: in this case, both Pessoa and Empresa already exists in the db)

"The INSERT statement conflicted with the FOREIGN KEY constraint \"FK_dbo.FuncionarioFree_dbo.Empresa_EmpresaId\". The conflict occurred in database \"...", table \"dbo.Empresa\", column 'PessoaId'.\r\nThe statement has been terminated."

EDIT: I did some more tests and it works when i try to insert a new FuncionarioPagante with a Pessoa that has a Empresa. But that doesn't make sense to me. The Pessoa that i am inserting shouldn't had to have a Empresa in order to be inserted into a list of FuncionarioPagante in an Empresa of someone else.

EDIT 2: When i insert it with Empresa it works as well, like this:

var empresa = _contexto.Empresa.Where(x => x.EmpresaId == empresaId).FirstOrDefault();

var novoFuncionario = new FuncionarioPagante()
{
    EmpresaId = empresaId,
    Pessoa = pessoaUnidade.Pessoa,
    Empresa = empresa,
    PessoaId = pessoaUnidade.PessoaId
};

But the value inserted in EmpresaId changes to the value of PessoaId of the owner of the Empresa after SaveChanges()

  • When you debug the insert statement, prior to the insert, did it have the correct value for PessoaId? – Rakesh Oct 08 '19 at 19:24
  • Yes, it has the correct value. I am inserting it into FuncionarioPagante, should i insert it directly into Empresa? – Gustavo de Paiva Caiafa Oct 08 '19 at 19:31
  • And the order is - you create Pessoa, then Empresa and finally the FuncionarioPagante. Check the DB schema for the foreignkey definition and make sure it is what you expect. – Rakesh Oct 08 '19 at 19:34
  • @Rakesh Yes, i am doing in that order. I checked the DB and its ok. I did some more tests and it works when i try to insert a new FuncionarioPagante with a Pessoa that has a Empresa. But that doesn't make sense to me. Pessoa shouldn't had to have a Empresa in order to be inserted into a list of FuncionarioPagante in an Empresa of someone else. – Gustavo de Paiva Caiafa Oct 09 '19 at 12:58

2 Answers2

0

Its likely because the state of the Pessoa is also changing to "added". Remove the line

Pessoa = pessoaUnidade.Pessoa,

and only set the ID. That should let it save correctly.

Your object graph is making it look like all entities are new. As an alternative you could explicitly set the Pessoa entity to an object state of "unmodified".

To verify this, before save chagnes you'd do something like (did not compile, but this is close) this...

var tmpState = _contexto.Entity<Pessoa>(pessoaUnidade.Pessoa).ObjectState;
//look at value of tmpState. it likely says "added" and you want it to be "unmodified"
kd345205
  • 319
  • 1
  • 8
  • I tried removing it but the error persists. The ObjectState of Pessoa is unchanged, so i dont think thats the problem. – Gustavo de Paiva Caiafa Oct 09 '19 at 12:54
  • Your model for Empresa dictates that the "key" is "pessoaId" can you check your database design and verify what the primary key is? This could be causing you issues because it seems like "EmpresaId" should be the PK and you're overriding that by using the "Key" attribute. To set a FK, you should not also use "Key" – kd345205 Oct 09 '19 at 19:14
  • Yes, the PK is PessoaId because the relantionship from Pessoa to Empresa is 1.0-1, so from what i read Pessoa Id has to be the primary key in Empresa as well. – Gustavo de Paiva Caiafa Oct 10 '19 at 11:28
  • I think there is an issue with the relationships you've defined but I'm struggling with the translations. Can you write a few statements to explain what the entity's are and how they are related (eg Person has a Company. Company has many people etc..)? I see you have a Person, Company and then A Free Officer (not shown) and Paying Officer but Im not positive what those are. I'm going to re-create this locally and try it. I really think the 0-1 or 0 is configured incorrectly. That relationship is difficult to follow and it took me a while to ever get it right. – kd345205 Oct 10 '19 at 12:24
  • Yeah i think the relantionship may be wrong too but i dont think the problem is in Person and Company,i followed this link to make an 1..0-1 relantionship: https://stackoverflow.com/questions/36742272/entity-framework-code-first-10-1-change-foreign-key-location So anyway, let me try and explain it: Person may or may not have a Company. That causes the 1..0-1 relantionship i mentioned above. And then Company has a list of FreeOfficer and PayingOfficer just like you said(they're the same), and those two tables(Officers) are just to link who the person is and what company they work for. – Gustavo de Paiva Caiafa Oct 10 '19 at 13:20
  • And something i think its worth mentioning: I think Company could just have a list of Person, but i think i need this third table(Officers) to search if someone is working on some Company based on PersonId and what Company is it. – Gustavo de Paiva Caiafa Oct 10 '19 at 13:25
  • The translation of FuncionarioPagante and FuncionarioFree are "paying officer" and "free officer" and I think I misinterpreted them. Are these lists representing people who are either associated with a company (FuncionarioPagante ) and those who are not (FuncionarioFree)? In other words, one list is people with a companyid, the other is people with companyid = null. correct? – kd345205 Oct 10 '19 at 13:53
  • Almost. I think it translates better to Employee. The "Paying" ones are those who work and are paid to.The free ones work but dont get paid(think of them kinda like interns who works half a day and dont get paid). But both have companyid, because to exists in this table(both free and paying) they have to be in a company. – Gustavo de Paiva Caiafa Oct 10 '19 at 14:19
  • ok, thank you. can a person belong to multiple companies? Do paid employees and unpaid employees HAVE to be in different tables or can their pay status be a property of the person itself? Eg. an enum for PayType – kd345205 Oct 10 '19 at 14:21
  • Sorry for taking too long to reply, i had some other things to finish. A person can belong just to one company. Yes i already changed the Employee table to be just one with a property to differ both. And something i think its worth mentioning: i did manage it to work, but only when i change Person so it can have a List of Companies and not just one. – Gustavo de Paiva Caiafa Oct 16 '19 at 17:43
  • You can remove your entity 'FuncionarioPagante'. It's acting like a join table to represent a many to many of person to company. Here you link to an person (who already has a companyid) and a compnay (duplicate). If you remove that table completely I think you'll be more successful. After that, a company has 2 navigation properties for a collection of person. I think you should remove one, have one navigation property of an ICollection and you can use a service class or repo wrapper to get employees based on its props. If you MUST keep both, we'll revisit. Update question if need be. – kd345205 Oct 16 '19 at 19:55
  • Alright, thanks, it makes sense. Im gonna try and i'll post back here if needed. – Gustavo de Paiva Caiafa Oct 18 '19 at 12:18
0

Can you modify the FuncionarioPagante to have a nullable value for EmpresaId

public class FuncionarioPagante
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int FuncionarioPaganteId { get; set; }
    public int PessoaId { get; set; }
    [ForeignKey("PessoaId")]
    public virtual Pessoa Pessoa { get; set; }
    public int? EmpresaId { get; set; }
    [ForeignKey("EmpresaId")]
    public virtual Empresa Empresa { get; set; }
}
Rakesh
  • 654
  • 4
  • 10
  • 23