none
EntityFramework expose foreign key error when saving association from within MVC Action Method RRS feed

  • Question

  • We are using MVC in combination with Entity Framework.

    At some point we are trying to establish a link between two entities.  This works fine in a unit-test, but gives the following error when tried from an MVC controller method:

    “An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. “

    The (stripped down) classes:

    public class Position : Entity
    {
       public string Function { get; set; }
       public Organization Organization{ get; set; }
       // public Guid? OrganizationId { get; set; }
       // works when enabled!
    }
    
    public class Organization: Entity
    {
       public string Name { get; set; } 
       public IList<Position> Contacts
       {
           get {return contacts;} 
           set { contacts = value; }
       }
     
       public class EntityConfiguration :
                EntityConfigurationBase<Organization>
       {
           public EntityConfiguration()
           {
               HasMany(p => p.Contacts)
                   .WithOptional(y => y.Organization)
            }
       }
     
       private IList<Position> contacts = 
           new List<Position>();
    }
    

    The (stripped down) controller method that fails:

    [HttpPost]
    public ActionResult Edit(Position position, string organizationId = "")
    {
        if (!ModelState.IsValid)
        {
            return View(position);
        }
        db.Entry(position).State = EntityState.Modified;
        if (!string.IsNullOrEmpty(organizationId))
        {
            Guid orgId = Guid.Parse(organizationId);
            Organization organization =
                db.Organizations
                    .First(x => x.Id.Equals(orgId));
            position.Organization = organization;
        }
    	db.SaveChanges();
        RedirectToAction("Index");
    }

     

    The unit test that passes:

    [TestMethod]
    public void LinkOrganizationToPositionTest()
    {
        // arrange
        DbModel dbModel;
        Organization org;
        Position pos;
        Guid orgId;
    
        using (dbModel = new DbModel())
        {
            dbModel.Database.Delete();
            dbModel.Database.Create();
    
            // - first organization
            org = dbModel.Organizations.Create();
            org.Name = "TestOrgFirst";
            dbModel.Entry(org).State = EntityState.Added;
    
            pos = dbModel.Positions.Create();
            pos.Function = "TestFunc";
            dbModel.Entry(pos).State = EntityState.Added;
    
            // - link pos to first org
            pos.Organization = org;
    
            org = dbModel.Organizations.Create();
            org.Name = "TestOrgSecond";
            dbModel.Entry(org).State = EntityState.Added;
            orgId = org.Id;
            dbModel.SaveChanges();
        }
    
        // act
        // - obtain "fresh" model
        using (dbModel = new DbModel())
        {
            // - get second org
            org = dbModel.Organizations.Find(orgId);
            pos = dbModel.Positions.Find(pos.Id);
            pos.Organization = org;
            dbModel.SaveChanges();
        }
    
        // assert
        using (dbModel = new DbModel())
        {
            Position actual =
                dbModel.Positions
                    .Include("Organization")
                        .First(x => x.Id.Equals(pos.Id));
            // - link was saved 
            Assert.AreEqual(
                "TestOrgSecond", 
                actual.Organization.Name
                );
        }
    }

           
    
    
    Why is the is the OrganizationId foreign key property required by the MVC?
     Is there a simple fix that doesn’t require  all the foreign-keys in the model?
    Friday, October 11, 2013 12:43 PM

All replies

  • This is not a MVC issue. This is an EF issue with the way you have defined the entities that EF is using for CRUD operations with the database.

    What are the properties in one of your EF entities

    <copied>

    “An error occurred while saving entities that do not expose foreign key properties for their relationships.

    <end>

    EF is telling you what is wrong. Where is the foreign-key property on the child entity that ties it to its parent entity so EF and populate it? 

    Friday, October 11, 2013 3:37 PM
  • That is the point: There is no foreign key property. Nor should it need one; the unit test works and doesn't use foreign keys either. EF code first produces a DB schema that has the a foreign key column in the position table why should I want to change this?
    Monday, October 14, 2013 8:16 AM
  • <copied>

    the unit test works and doesn't use foreign keys either

    <end>

    A unit test implies that you only simulated it,  and nothing was actually saved to the database. Well that's what a UT is suppose to be doing supposedly.

    EF (for real) doesn't like what you are trying to do here when you did the save.

    Monday, October 14, 2013 1:05 PM
  • No, the database is deleted, recreated, objects that are added are stored. This may not be a Unit Test to purists, but they are useful non the less as the validate the key actions on the domain model...
    Monday, October 14, 2013 1:24 PM
  •  

    <copied>

    This may not be a Unit Test to purists, but they are useful non the less as the validate the key actions on the domain model...

    <end>

    The interactions of objects on the domain model is one thing and the interactions of the objects on the virtual model of the ORM are two different things.

    • Marked as answer by Fred BaoModerator Friday, October 18, 2013 9:58 AM
    • Unmarked as answer by ksighem Monday, November 4, 2013 8:09 AM
    Monday, October 14, 2013 1:47 PM
  • I have no idea why this comment was marked as an answer by Fred. The answer voices an opinion that has virtually no bearing on the original question.

    I wan't to know how both (MS recommended techs) interact produce this result. To say that they are not related is BS, if I generate controller/view templates both techs are combined, so I want to know how they work together.  


    • Edited by ksighem Monday, November 4, 2013 8:16 AM
    Monday, November 4, 2013 8:11 AM
  • <copied>

    I have no idea why this comment was marked as an answer by Fred. The answer voices an opinion that has virtually no bearing on the original question.

    I wan't to know how both (MS recommended techs) interact produce this result. To say that they are not related is BS, if I generate controller/view templates both techs are combined, so I want to know how they work together.  

    <end>

    No,  both technologies are NOT COMBINED, because you can certainly use MVC without EF PERIOD, just like one can use MVVM and MVP without EF period or use EF with either one of the design patterns. MVC is a design pattern by the way and NOT a technology. Just because you can't figure it out with trying to tell EF something that it cannot do, don't put it on anyone or anything else but yourself.  You are the one that's going to have to deal with it. You are the one who has to figure out something that EF is clearly telling  you is not acceptable.

    And then you have the audacity to say that objects on the domain model and you tested it should apply to what's happening on the ORM virtual model objects, objects persisted to database, should be the same, which is an outrageous assumption on your part.

    Monday, November 4, 2013 4:56 PM
  • Look I don't want to start an argument, I want an answer why things work as they do.  Yes you can use MVC with with say NHibernate or plain vanilla SQL.

    And yes you can use EF with Winforms, ASP forms, console apps and what have you. 

    But I'm not, and I want to understand why the sample code works when I perform it form simple C# code, the unit test, and why it gets buggered up when I do it from MVC so I can fix my code. 

    What Fred said may have been true, but it is not an answer why the things happened as they did.

    I have since added foreign key navigation properties. Which isn't very OO in the way they work. You can now add things to collections without the owner ever knowing let alone be able to validate the addiction...

    But if it makes MVC/EF happier so, then so be it.

    I'm done here guys.



    • Marked as answer by ksighem Sunday, November 10, 2013 10:58 PM
    • Unmarked as answer by ksighem Sunday, November 10, 2013 10:58 PM
    • Edited by ksighem Sunday, November 10, 2013 10:59 PM
    Sunday, November 10, 2013 10:53 PM
  • <copied>

    I have since added foreign key navigation properties. Which isn't very OO in the way they work. You can now add things to collections without the owner ever knowing let alone be able to validate the addiction...

    <end>

    You were told how to correct the problem several weeks ago, which was to get the needed property in the object so that the object could be persisted to the database. LOL! Properties are in an entity/object,  and it doesn't get anymore OO than that. :)  I don't even know what you are talking about and nether do you. Navigation has to do with relationships in working with relational databases and an ORM (Object Relational Mapping), and it has nothing to do with OO.

    Maybe you should start with backing off of the MVC3 or 4  and EF combination crutch the next time and use MVC with BLL, DAL and the EF model behind the DAL  (N-Tier) where one has absolute control of everything validation and all, which can be used in MVC.

    It's you with the bad design here that is the possible problem here.

    Monday, November 11, 2013 1:09 AM
  • @darnold924: I'm glad I could add some "LOL" to your otherwise pretty sad day, considering the time you spend pissing off people online
    Wednesday, November 13, 2013 12:51 PM
  • <copied>

    @darnold924: I'm glad I could add some "LOL" to your otherwise pretty sad day, considering the time you spend pissing off people online

    <end>

    Hey, don't kill the messenger...... I gave it to you point blank with no punches pulled. It is what it is.  I start a new MVC contract project where I basically have to write the entire solution from scratch using EF and Oracle starting this Thursday. This will be my first MVC project from a professional level. You have clearly shown me what not to do.

    Wednesday, November 13, 2013 8:31 PM
  • @darnold924: I did implement the Foreign-Key fix several weeks ago. And yes I'm still content with using EF.

    Although it works different then some ORMs I have used in the past obviously need FK's as well, but don't have the need to expose them the resulting domain model (check out Devexpress XPO or even NHibernate).

    All I wanted was gaining some understanding how MVC and EF interacted that made a solution that worked fine when I made the links in the code of my unit-test, and would not when invoked from MVC.

    I've never gotten a "because", but I do have and use wat is essentially a work arround.

    What I didn't need was discussion on whether my sample was a "unit test" or whether or not to use domain classes as "M" in MVC etc. Your "LOL" post broke the camels back, I apologize

    Thursday, November 14, 2013 11:36 AM
  • <copied>

    I have no idea why this comment was marked as an answer by Fred. The answer voices an opinion that has virtually no bearing on the original question.

    <end>

    That statement from you somewhat set all this in motion. 

    <copied>

    All I wanted was gaining some understanding how MVC and EF interacted that made a solution that worked fine when I made the links in the code of my unit-test, and would not when invoked from MVC.

    <end>

    Well, you should have done a integration or functional test with a test harness using a BLL/DAL pattern or a Service Layer with UOW/Repository pattern and tested it well before you started with MVC and getting caught at the UI level.  You could have exposed it well before you got to MVC.  You could have expose the situation without MVC being involved.

    <copied>

    I've never gotten a "because", but I do have and use wat is essentially a work arround.

    <end>

    It's not a work around. It's how EF works. The primary and foreign key properties must be in the objects in order to persist the objects to the database. EF will not work without  them being there, if using the model first approach,  that would have been exposed out the gate. I don't know, maybe you didn't do your homework.

    <copied>

    What I didn't need was discussion on whether my sample was a "unit test" or whether or not to use domain classes as "M" in MVC etc.

    <end>

    You needed to be told look at what happened due to you not knowing the difference between a domain model object as opposed to ORM virtual model object and assuming that the domain object is a ORM object.

    http://msdn.microsoft.com/en-us/magazine/ee236415.aspx

    Not trying to be smart here, but maybe you need to learn how to architect.

    http://www.dofactory.com/framework/framework.aspx

    You may not like what I told you, but it is what it is.

    Friday, November 15, 2013 11:03 PM