81

Here is my model of 3 entities: Route, Location and LocationInRoute.
model

the following method fails and get exception when commit it:

 public static Route InsertRouteIfNotExists(Guid companyId, IListLocation> locations)
        {
            //Loop on locations and insert it without commit
            InsertLocations(companyId, routesOrLocations);

            RouteRepository routeRep = new RouteRepository();
            Route route = routeRep.FindRoute(companyId, locations);
            if (route == null)
            {
                route = new Route()
                {
                    CompanyId = companyId,
                    IsDeleted = false
                };
                routeRep.Insert(route);
                LocationInRouteRepository locInRouteRep = new LocationInRouteRepository();
                for (int i = 0; i < locations.Count; i++)
                {
                    locInRouteRep.Insert(new LocationInRoute()
                    {
                        //Id = i,
                        LocationId = locations[i].Id,
                        Order = i,
                        RouteId = route.Id
                    });
                }
            }
            return route;
        }

When doing:

InsertRouteIfNotExists(companyId, locations);
UnitOfWork.Commit();

I got:

Unable to determine the principal end of the 'SimTaskModel.FK_T_STF_SUB_LOCATION_IN_ROUTE_T_STF_LOCATION_location_id' relationship. Multiple added entities may have the same primary key.

When splitting the commit and insert in into the methos - it works:

  public static Route InsertRouteIfNotExists(Guid companyId, IListLocation> locations)
            {
                //Loop on locations and insert it without commit
                InsertLocations(companyId, routesOrLocations);
                UnitOfWork.Commit();

                RouteRepository routeRep = new RouteRepository();
                Route route = routeRep.FindRoute(companyId, locations);
                if (route == null)
                {
                    route = new Route()
                    {
                        CompanyId = companyId,
                        IsDeleted = false
                    };
                    routeRep.Insert(route);
                    LocationInRouteRepository locInRouteRep = new LocationInRouteRepository();
                    for (int i = 0; i < locations.Count; i++)
                    {
                        locInRouteRep.Insert(new LocationInRoute()
                        {
                            //Id = i,
                            LocationId = locations[i].Id,
                            Order = i,
                            RouteId = route.Id
                        });
                    }
                    UnitOfWork.Commit();
                }
                return route;
            }

I would like to call commit once and outside the method. Why it fails in the first example and what does this exception means?

Sefe
  • 13,731
  • 5
  • 42
  • 55
Naor
  • 23,465
  • 48
  • 152
  • 268
  • 9
    @Ladislav Mrnka: I have no boss and this is project of mine. I really don't know where you get the impression that I immediately ask on SO. You are not the only one who uses the computer all day long. Consultancy for free? does someone give anyone guarantee for his answers? I believe this is a forum where questions can be asked here and this is what I am doing. I have many questions and I believe I make a long distance of learning thanks to this forum and people like you. The participation is a choise. – Naor May 18 '11 at 07:35
  • 1
    @Ladislav: I only see a reasonably well asked question, and the OP's profile doesn't indicate anything over the top either. – H H May 18 '11 at 09:22
  • Are you using same ObjectContext throughout scope of operation or each new Repository will have its own ObjectContext? – Akash Kava May 19 '11 at 15:51
  • @Akash Kava: I am using the same ObjectContext. – Naor May 19 '11 at 16:48

5 Answers5

149

The error is caused by a foreign key ID (as opposed to a reference) which cannot be resolved. In your case, you have a LocationInRole that references a Location with an ID of 0. There are multiple Locations with this ID.

The Locations have not yet been assigned an ID because they have not yet been saved to the database which is when the ID is generated. In your second example, the Locations are saved before their IDs are accessed which is why this works.

You will not be able to rely on the Location IDs to define the relationships if you want to SaveChanges only later.

Swap the following line...

LocationId = locations[i].Id

...for this...

Location = locations[i]

The relationships will then be based on object references which are not dependent on the LocationIDs.

Scott Munro
  • 13,369
  • 3
  • 74
  • 80
  • can either of you take a look at my post and tell me how I can fix it, I'm getting the same issue: http://stackoverflow.com/questions/26783934/foreign-key-cycles-or-cascade-paths I appreciate it! – Abdul Ahmad Nov 06 '14 at 23:44
  • I am getting this error when i deploy to test env...not in dev environemnet any ideas? – Taran Aug 19 '16 at 22:48
  • @Taran If the code is identical and you are using the same process to test in both environments (I would check these points) then this does seem strange. Maybe you are adding only a single location (following on with the example here) in dev? Try adding at least two. – Scott Munro Aug 22 '16 at 08:38
  • My problem may be a variation of this one. I was adding the child objects to the parent's collection without explicitly setting the parent property on the children. I expected EF to resolve this, but received the same error as the OP until I explicitly set the parent property on the child. Hope this helps someone. – Eric H Jan 28 '19 at 19:54
4

In case this is of any use to future readers, in my case this error was due to an incorrectly configured foreign key in my database (and model generated from DB).

I had tables:

Parent (1-1) Child (1-many) Grandchild

and the Grandchild table had inadvertently received a foreign key up to it's parent (Child) and it's grandparent (Parent). On saving multiple Parent entities from new, I received this error. Fix has been to correct the foreign key.

Paddy
  • 33,309
  • 15
  • 79
  • 114
  • In my case I had (stupidly) set my Primary Key Base Table the same as my Foreign Key Base Table and my Primary Key Column the same as my Foreign Key Column *bows head in shame* Hope this helps someone.. – Dave Aug 16 '16 at 13:21
3

Having run into the same error I highly suspect the actual issue was the definition of Location. Put simply, in EF Code First I bet it looked like this:

public class Location
{
    public int Id { get; set; }
    ...
    public Location ParentLocation { get; set; }
    [ForeignKey("ParentLocation")]
    public int ParentLocationId { get; set; }
}

In other words, in the Question, ParentLocation/ParentLocationId are a recursive reference back to this table.

The ParentLocationId is not Nullable. That means it's going to be inserted with a 0, and EF will complain on Insert, rather than when you Migrate - even though the truth is once that Migration runs you have a table EF will never let you insert into.

The only way to make a recursive reference back to the same table work is to make the recursive reference nullable:

public class Location
{
    public int Id { get; set; }
    ...
    public Location ParentLocation { get; set; }
    [ForeignKey("ParentLocation")]
    public int? ParentLocationId { get; set; }
}

Note the ? after the int.

coolboyjules
  • 2,300
  • 4
  • 22
  • 42
Chris Moschini
  • 36,764
  • 19
  • 160
  • 190
0

For those searching for this exception:
In my case, it was failing to set a required navigation property.

public class Question
{
    //...
    public int QuestionGridItemID { get; set; }
    public virtual QuestionGridItem GridItem { get; set; }
    //...
    public int? OtherQuestionID { get; set; }
    public Question OtherQuestion { get; set; }
}

//...

question.OtherQuestion = otherQuestion;
questionGridItem.Questions.Add(question);
dataContext.SaveChanges(); //fails because otherQuestion wasn't added to 
//any grid item's Question collection
R. Salisbury
  • 1,954
  • 16
  • 17
0

i had same problem. with below scenario solved for me. i think you must change your code such as below:

var insertedRoute =routeRep.Insert(route);
.....
insertedRoute.LocationInRoute = new List<LocationInRoute>();
for(....){
    var lInRoute = new LocationInRoute(){
    ....
    Route=insertedRoute;
}

insertedRoute.LocationInRoute.Add(lInRoute );
}