11

I have started with C# and I wanted to make my own DB.

I have two models

public class AModel 
{
    public Guid ID { get; private set; }
    public string Name { get; set; }
    public int Count { get; set; }
    public AModel()
    {
        this.ID = Guid.NewGuid();
    }
}

public class BModel 
{
    public Guid ID { get; private set; }
    public string Name { get; set; }
    public AModel Model { get; set; }
    public BModel()
    {
        this.ID = Guid.NewGuid();
    }
}

When I try to save BModel to DB, I get this error:

Violation of PRIMARY KEY constraint 'PK_dbo.AModels'. Cannot insert duplicate key in object 'dbo.AModels'. The duplicate key value is (48ee1711-8da4-46c1-a714-19e985211fed).\r\nThe statement has been terminated.

I thought it would be solved by this

modelBuilder.Entity<BModel>().HasRequired(t => t.Model).WithMany();

but it looks like I am completely lost. Could anybody help me with this simple example?

Jeroen Vannevel
  • 43,651
  • 22
  • 107
  • 170
Tomas Bruckner
  • 718
  • 2
  • 10
  • 22
  • The error message is cryptic because chances of duplicate keys with a Guid are astronomically unlikely. What I do suspect however is that because of incorrect mapping, it's trying to create multiple identical foreign keys. What happens if you use `modelBuilder.Entity().HasRequired(t => t.Model).WithMany().Map(x => { x.ToTable("BAs"); x.MapLeftKey("BId"); x.MapRightKey("AId"); });`? – Jeroen Vannevel Apr 18 '15 at 19:12
  • 2
    I am not making new instance of AModel when creating BModel, but instead, I am choosing one already created instance of AModel from Combobox. I just want it to create reference from BModel to AModel. – Tomas Bruckner Apr 18 '15 at 19:24
  • How will this work ? you are creating a new GUID everytime new model is created. and there is a private set. When it fetches a Mode from data how will it assign value to ID ? – Bilal Fazlani Apr 18 '15 at 19:40

1 Answers1

16

Your comment reveals vital information. When you add that AModel from your combobox to your BModel, it will have become detached from your DbContext by then. When you then add it to your model, Entity Framework will think that you have a new object.

Since you have your Ids configured as DatabaseGenerationOptions.None, it will use the primary key you provide yourself. In your case this is the PK of the detached object. Thus, when EF tries to insert this entry it will throw the above exception because an entity with that key is already in there.

There are a few ways to solve this:

  • Retrieve the existing entity

This entity will be attached to your context upon retrieval, allowing you to use this. This means an extra lookup however: first to get them into the combobox and then to use the Id from the entity in the combobox to retrieve it again from the database.

Example usage:

AModel Get(AModel detachedModel)
{
    using(var context = new MyContext())
    {
        return context.AModels.Single(x => x.ID == detachedModel.ID);
    }
}
  • Attach the existing model

This should just make Entity-Framework aware that the entity already exists in the database.

using(var context = new MyContext())
{
    context.AModels.Attach(detachedModel);
}

Other ways to attach is by setting the state to Unchanged

context.Entry(detachedModel).State = EntityState.Unchanged;

or Modified (in case you also changed values)

context.Entry(detachedModel).State = EntityState.Modified;
Jeroen Vannevel
  • 43,651
  • 22
  • 107
  • 170