3

I have an ASP.NET MVC 4 application using Entity Framework 5 under .NET 4.5. The problem I'm having is that when I insert a detached entity that was created on the front-end, the lazy loading is not working.

Here is my code to add (or update):

public static int PersistMergeEntity(EntityTwo entityTwo)
{
    int entityId;

    using (var _db = new EntityDb())
    {
        if (_db.EntityTwo.Any(e => e.EntityTwoId == entityTwo.EntityTwoId))
        {
            _db.Entry(entityTwo).State = EntityState.Modified;
        }
        else
        {
            _db.EntityTwo.Add(entityTwo);
        }

        _db.SaveChanges();

        //_db.Entry(entityTwo).Reference(e => e.EntityOne).Load();
        entityId = entityTwo.EntityOne.EntityId;
    }

    EntityBo.UpdateData(entityId);

    return entityTwo.EntityTwoId;
}

Here are my entities:

public class EntityTwo
{
    [Key]
    [ForeignKey("EntityOne")]
    public int EntityTwoId { get; set; }

    public Decimal NbValue { get; set; }

    public virtual EntityOne EntityOne { get; set; }
}

public class EntityOne
{
    [Key]
    [ForeignKey("EntityTwo")]
    public int EntityOneId { get; set; }

    [ForeignKey("Entity")]
    public int EntityId { get; set; }

    public CsMonthDomain CsMonth { get; set; }
    public int NbYear { get; set; }
    public Decimal NbValue { get; set; }

    public virtual Entity Entity { get; set; }
    public virtual EntityTwo EntityTwo { get; set; }
}

And Entity is another entity that I need to do calculation every time I update or add EntityTwo.

The code works when the commented line is uncommented. But if it is the way shown up there, lazy loading will not work and I'll get a null Exception. Lazy loading is set to true and the entities are, supposedly, correct, since it works when I explicitly load the navigation property.

I'm sorry about the names, but unfortunately I cannot post the real code ;(

7hi4g0
  • 3,729
  • 4
  • 22
  • 32

1 Answers1

3

Lazy loading does not work because the entityTwo you pass into the method is (most likely) not a dynamic proxy which it has to be in order to make lazy loading work. The instance is probably created outside the method using entityTwo = new EntityTwo();. To create a proxy of an entity you would need a context instance available and then use

entityTwo = _db.EntityTwos.Create();

In my opinion using explicit loading (your commented line) is the best solution in this situation. It has the same costs of querying the database once per navigation property like lazy loading would have plus the additional benefit over lazy loading that you could project a selection of properties you only need from the related entity, for example:

entityId = _db.Entry(entityTwo).Reference(eTwo => eTwo.EntityOne).Query()
    .Select(eOne => eOne.EntityId)
    .Single();
Slauma
  • 175,098
  • 59
  • 401
  • 420
  • Thank you for your reply! I'm still fairly new to C# and family and I'm still building my way up :) Liked the suggestion to use `.Query().Select().Single();`, but I'm still upset I couldn't simply use Lazy loading. Also, you are correct about `EntityTwo`, it's created on my Controller using the builtin ModelBuilder. – 7hi4g0 Jul 16 '13 at 21:11
  • @7hi4g0: The model binder probably uses the instance activator from the reflection API, but in this context it's basically the same as calling `new` -> no dynamic proxy. Take a positive look at it: Not having lazy loading saves you some poor performance surprises because you wrote a dot accidentally somewhere without being aware that it causes to run an expensive query. With explicit loading you have at least a line in code that makes it clear :) – Slauma Jul 16 '13 at 21:30
  • There is a generic repository method here http://stackoverflow.com/a/16811976/150342 that can be used to Create and Update detached entities that inherit from a base Model with an ID. It uses the Create method to ensure a proxy is always created – Colin Jul 17 '13 at 08:01