views:

1792

answers:

5

I'm building an ASP.NET MVC site using the ADO.NET Entity Framework. I have an entity model that includes these entities, associated by foreign keys:

Report(ID, Date, Heading, Report_Type_ID, etc.)

  • SubReport(ID, ReportText, etc.) - one-to-one relationship with Report.
    • ReportSource(ID, Name, Description) - one-to-many relationship with Sub_Report.
      • ReportSourceType(ID, Name, Description) - one-to-many relationship with ReportSource.
      • Contact (ID, Name, Address, etc.) - one-to-one relationship with Report_Source.

There is a Create.aspx page for each type of SubReport. The post event method returns a new Sub_Report entity.

Before, in my post method, I followed this process:

  1. Set the properties for a new Report entity from the page's fields.
  2. Set the SubReport entity's specific properties from the page's fields.
  3. Set the SubReport entity's Report to the new Report entity created in 1.
  4. Given an ID provided by the page, look up the ReportSource and set the Sub_Report entity's ReportSource to the found entity.
  5. SaveChanges.

This workflow succeeded just fine for a couple of weeks. Then last week something changed and it doesn't work any more. Now instead of the save operation, I get this Exception:

UpdateException: "Entities in 'DIR2_5Entities.ReportSourceSet' 
participate in the 'FK_ReportSources_ReportSourceTypes' relationship. 
0 related 'ReportSourceTypes' were found. 1 'Report_Source_Types' is expected."

The debug visualizer shows the following:

  • The SubReport's ReportSource is set and loaded, and all of its properties are correct.
  • The Report_Source has a valid ReportSourceType entity attached.

In SQL Profiler the prepared SQL statement looks OK. Can anybody point me to what obvious thing I'm missing?

TIA

Notes: The Report and SubReport are always new entities in this case. The Report entity contains properties common to many types of reports and is used for generic queries. SubReports are specific reports with extra parameters varying by type. There is actually a different entity set for each type of SubReport, but this question applies to all of them, so I use SubReport as a simplified example.

A: 

Check if your ReportSource was loaded with the NoTracking option or if its EntityState == 'Detached'. If so, that is your problem, it must be loaded in the context.

ADB
Thanks for the comment. I'd already checked the EntityState in debug mode, but not the NoTracking option. I did try it prompted by your comment, with no joy. I also re-generated my model to see if the last update had caused a problem, but it didn't make a difference. To get past this, I just wrote a stored procedure to clean up any related objects and delete the entity.
Tim Rourke
A: 

This tends to happen if your database tables have a 1 - 1 relationship with each other. In your example reportsourceset expects a reportsorttypes with whatever id it is referencing. I have run into this problem when my relationship is linking two primary keys from opposite tables together.

Ramone Hamilton
+1  A: 

I realise I'm late to this, but I had a similar problem and I hacked through it for about 3 hours before I came up with a solution. I'd post code, but it's at home - I can do it later if someone needs it.

Here are some things to check:

  • Set a breakpoint on the SaveChanges() call and examine the object context in depth. You should see a list of additions and changes to the context. When I first looked, I found that it was trying to add all my related objects rather than just point to them. In your case, the context might be trying to add a new Report_Source_Type.
  • Related to the previous point, but if you're retrieving the report source, make sure it is being retrieved from the database by its entity key and properly attached to the context. If not, your context might believe it to be a new item and therefore its required relationships won't be set.

From memory, I retrieved my references using the context.GetObjectByKey method, and then explicitly attached those objects to the context using the context.Attach method before assigning them to the properties of my original object.

Damovisa
The list of additions and changes can be found using the Visual Studio DataTip (Set a breakpoint on the line that is similar to the one below and hover over the ObjectContext part).this.ObjectContext.SaveChanges().In the DataTip, drill down to '_addedEntityStore' via...base {System.Data.Objects.ObjectContext } ->ObjectStateManager ->Non-Public members ->_addedEntityStore
mathijsuitmegen
That's what I do when I'm running in debug. In my case, an inspection of the runtime properties showed that all data was in place, all keys were populated and correct. I think the EF just doesn't keep track of things to the level one would expect. I was in a hurry when I posted, so I just decided to use stored procedures to handle saving complex entity trees.
Tim Rourke
A: 

I've got the same error because of new object instance which created "behind the scene" in "Added" state. This was not obvious.

Ratamahatta
It sure isn't obvious. In my case I'm writing tools that will be maintained by others and I couldn't in good conscience leave such a situation for them to deal with, so I split out tasks into stored procedures for the complex entities.
Tim Rourke
A: 

I got this error because the table didn't have a primary key, it had a FK reference, but no PK.

After adding a PK and updating the model all is well.