2

I'm using EF6 with code first migrations to create my database. I made a mistake with my models, but am struggling to understand why this is happening.

I have two tables

[TrackChanges]
public class Loan
{
    public long Id { get; set; }
    ....
    public virtual LoanAddress LoanAddress { get; set; }

    public Loan() {
        LoanAddress = new LoanAddress();
    }
}

[TrackChanges]
public class LoanAddress
{
    public long Id { get; set; }
    ...
}

When I create a new Loan with a new LoanAddress, it usually creates two LoanAddresses. One's assigned to the Loan and the other is an orphan.

    public async Task<IHttpActionResult> Create(LoanViewModel l)
    {
        try
        {
            Loan loan = new Loan
            {
                //LoanAddress = new LoanAddress(),
                ...
            };

            dbContext.Loan.Add(loan);
            await dbContext.SaveChangesAsync(currentUserName);

            return Ok(loan.Id);
        }
        catch (Exception ex)
        {
            ....
        }
    }

If I debug and step through, dbContext.LoanAddress has two entries in Local.

What's really confusing me is this doesn't happen when

  • The database is empty (it creates one record)
  • Sometimes when I debug the code and watch LoanAddress it acts fine
  • I do something similar using the database seed method. It behaves fine here

One thing that doesn't help is LoanAddress not having a reference back to Loan. That was a mistake (is this one to many without?), but using code-first migrations struggles to fix it. I have live data in the table, and am unsure if I can fix that.

Otherwise, creates and updates work, just that creating Loans creates orphaned rows.

  • You better put the fixing part in another question focusing on the mapping details of the two classes. Maybe it can be fixed, but that depends on how they are mapped now. – Gert Arnold Apr 12 '16 at 21:18

1 Answers1

0

First, never initialize reference navigation properties in entity constructors. Here I've explained why not.

It's a bit surprising that this also causes an orphan LoanAddress to be created, because in your code the default instance (from the constructor) is never attached to the change tracker, because it is replaced by a new instance before the Loan is added. Maybe this happens when you update existing Loans.

Second, if you Add an entity, all entities belonging to it are also marked as Added (if they were not yet attached to the context). I assume that you actually intend to have one new LoanAddress here, so that should be OK.

Community
  • 1
  • 1
Gert Arnold
  • 105,341
  • 31
  • 202
  • 291
  • Thanks! That seems to work and makes sense. That drove me nuts. I thought doing something like LoanAddress = new LoanAddress() would be good enough, but needed to remove the entire constructor piece for it to apply. I'm not entirely sure why it did that, or why my other method that created new Loans worked while this didn't. It didn't actively replace the LoanAddress either, though it accessed the LoanAddress object beforehand. – fred repetition Apr 12 '16 at 21:38