2

Paraphrasing from this MSDN documentation ...

An INSERT statement is generated by the Entity Framework and executed on the data source when SaveChanges is called on the ObjectContext.

If the INSERT operation succeeds, server-generated values are written back to the ObjectStateEntry. When AcceptChanges is called automatically at the end of the SaveChanges execution, a permanent EntityKey is computed by using the new server-generated values.

This does not seem to be occurring in my code. When I call ObjectContext.SaveChanges(), an UpdateException is thrown with InnerException.Message value:

"duplicate key value violates unique constraint student_term_data_pkey"

Here is the offending code:

using (DataAccessLayerEntities context = new DataAccessLayerEntities()) {
     StudentTermData mostCurrent = new StudentTermData() {
          // Foreign keys:    
          StudentId = studentId,
          TermId = currentTerm.Id,

          // Non-nullable properties:
          SponsorCode = string.Empty,
          AdmissionNumber = string.Empty,
          Expiration = string.Empty
     };

     context.StudentTermDatas.AddObject(mostCurrent);
     context.SaveChanges();  // UpdateException occurs here.
}

I have verified that StudentTermData.Id is marked as an EntityKey in my Entity data model. Does anyone have any ideas or suggestions?

Rob
  • 5,223
  • 5
  • 41
  • 62
  • Can you should the DDL for StudentTermData, in particular the Id field, is it actually being generated on the server? – Ian Mercer Sep 09 '10 at 16:57
  • Any reason you are using the Id fields and adding the StudentTermData to the objectContext manually instead of simply doing `mostCurrent.Students.Add(student)` and `mostCurrent.Term = currentTerm` after creating an instance of it? (Assuming you can use a single objectContext to load them and apply them) – Ian Mercer Sep 09 '10 at 16:59
  • The student ID is obtained as-is from the SelectedValue of a ComboBox, which isn't bound to a collection of Students, so that's why I don't use mostCurrent.Students.Add(student). Also, the term is passed as an argument to the function after being loaded by a separate ObjectContext. – Rob Sep 09 '10 at 20:17
  • Also, I'm not sure what you mean in your first comment. Do you want the schema for student_term_data? Or just the INSERT query that gets generated? – Rob Sep 09 '10 at 20:19

2 Answers2

2

This problem was caused by a bug in EF4 where the EF designer doesn't set the StoreGeneratedPattern attribute in the SSDL. The problem is documented in this blog and this Microsoft Connect ticket.

The solution was to open my model's .edml file in a text editor, locate the <EntityType Name="student_term_data"> XML tag, and add StoreGeneratedPattern="Identity" to the property tag being used as an EntityKey:

  <EntityType Name="student_term_data">
     <Key><PropertyRef Name="id" /></Key>
     <Property Name="id" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
     ...
  </EntityType>

I then re-opened my model in the EF designer, made a small change (moved an entity position) and saved. This caused the code generator to run, presumably synchronizing the CDSL with the SSDL.

My code now runs as expected.

Rob
  • 5,223
  • 5
  • 41
  • 62
  • There is also another work-around listed on the Microsoft ticket that uses third-party "model comparer" software to synchronize the SSDL and CDSL, without having to manually modify XML. – Rob Sep 10 '10 at 18:56
0

EDIT

If you are trying to do an insert, then do not fill in the PK field (I'm guessing that's StudentID).

Tony Abrams
  • 4,505
  • 3
  • 25
  • 32
  • Sorry, I should have clarified. The primary key is simply titled Id, StudentId is a foreign key. – Rob Sep 07 '10 at 19:00