0

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?

k.c.
  • 1,755
  • 1
  • 29
  • 53
  • 3
    I can heartily recommend implementing the foreign keys explicitly. It makes life that much easier! – Dabblernl Oct 11 '13 at 13:57
  • Just curious.Have you tried to add the Position to the contacts of the Organization instead? – ilmatte Oct 11 '13 at 14:11
  • @ilmatte: Yes I have tried even adding position to the collection in Organization AND setting the Organization in Position – k.c. Oct 11 '13 at 15:08
  • @Dabblernl: I can see it going that way, but that is worse than ugly: OO implementations should not need relational foreign keys. – k.c. Oct 11 '13 at 15:10
  • 1
    @kc Read about the advantages of foreign key associations vs. independent associations (without primitive FK properties). The EF class model is still a DAL whichever way you look at it, so optimize it for its primary responsibility. You already have primary keys, a base class `Entity`, nested mapping classes. Primitive FKs don't make it any "worse" :) – Gert Arnold Oct 11 '13 at 20:53
  • @GertArnold: I'm rewriting my code at this time. I still don't understand WHY. Why have both ways in the first place if one works and one sucks. Why does a unit test do it flawless, and why does MVC EF combo explode... I left NHibernate because it fought back, look like I jumped from the frying-pan into the fire :'-( – k.c. Oct 14 '13 at 09:25
  • No, you jumped into another frying pan, which I'm sure in the end will turn out to be less hot. The main point is that IQueryable is a [leaky abstraction](http://blog.ploeh.dk/2012/03/26/IQueryableTisTightCoupling/). Which means that [LINQ != LINQ](http://stackoverflow.com/a/13352779/861716). This may seem an unacceptable truth, but we have to live with it, no choice. The reason why I'm sure that you won't regret your decision is that EF is much much better at LINQ than NHibernate. AFAIK, linq-to-nhibernate is still buggy and it's hard to tell when (and whether) it'll grow reliable. – Gert Arnold Oct 14 '13 at 09:46
  • @GertArnold: I rewrote the code and the impact was indeed minimal, and could be simplified in places. It's not likely I will ever go back to nHibernate willingly. I just hope will not over engineer EF over time as has happened with nHibernate over time... – k.c. Oct 14 '13 at 13:16

0 Answers0