2

Im trying to give a list of propertynames to my entity framework update method and these propertynames should be marked as unchanged. However It does get the properties, but than it gives the following error when trying to change the state:

The entity type RuntimePropertyInfo is not part of the model for the current context.

Which makes sense but Is there a way to get the object property that is on the current context?

Here is my code:

if (propertiesToSkip != null)
        {
            foreach (var propertyName in propertiesToSkip)
            {
                var prop = entity.GetType().GetProperty(propertyName);
                _context.Entry(prop).State = EntityState.Unchanged;
            }
        }

I hope anybody can help.

Edit

public static void MigrateIqrAccountDetails(ref IUnitOfWork uow, Account account,
        IEnumerable<List<string>> iqrContacts)
    {
        if (account.IqrAccount == null) throw new ArgumentException("Cannot migrate Account");

        // Addresses
        var addresses = ContactMigrationHelper.MigrateIqrContactAddresses(contact);
        if (addresses != null)
            account.Addresses.AddRange(addresses.Except(account.Addresses, new Comparers.AddressComparer()));
        uow.Repository<IqrAccount>().Update(account.IqrAccount);
        uow.Repository<Account>().Update(account, new List<string> {"Name"});
    }

Here is the method that edits the object and should update it on the context.

The account is being gathered like this:

var accountToUpdate =
            uow.Repository<Account>()
                .GetAll(a => a.IqrAccount != null, "PhoneNumbers", "EmailAddresses", "Addresses")
                .OrderBy(a => a.IqrAccount.UpdatedAt)
                .FirstOrDefault();

In the repository that looks like this:

public IEnumerable<T> GetAll(Func<T, bool> predicate = null, params string[] includes)
    {
        var query = Include(_objectSet, includes);
        return predicate != null ? query.Where(predicate).Where(o => !o.IsRemoved) : query.Where(o => !o.IsRemoved);
    }

protected virtual IQueryable<T> Include(IQueryable<T> query, params string[] includes)
    {
        if (includes == null) return query;

        query = includes.Aggregate(query, (current, item) => current.Include(item));
        return query;
    }

and the error im getting is:

The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.Addresses_dbo.Accounts_AccountId". The conflict occurred in database "Test", table "dbo.Accounts", column 'Id'. The statement has been terminated.

When savechanges is called.

Also here are my models:

    public class Account : BaseEntity
{
    public int Id { get; set; }
    [Required]
    public string Name { get; set; }

    public virtual List<Address> Addresses { get; set; }

    public int? CommentCollectionId { get; set; }

    public virtual LabelCollection LabelCollection { get; set; }

    public virtual User AccountManager { get; set; }

    [ForeignKey("ParentAccount")]
    public virtual int? ParentAccountId { get; set; }
    public virtual Account ParentAccount { get; set; }
    public virtual ICollection<Account> SubAccounts { get; set; } 
}


public class Address : BaseEntity
{
    public int Id { get; set; }
    public string Country { get; set; }
    public string Region { get; set; }
    public string City { get; set; }
    public string Street { get; set; }
    public string Number { get; set; }
    public string NumberExtension { get; set; }
    public string ZipCode { get; set; }
    public bool IsActive { get; set; }
    public string Premise { get; set; }
    public string SubPremise { get; set; }
    public Location Coordinates { get; set; }

    [ForeignKey("Account")]
    public int AccountId { get; set; }
    public Account Account { get; set; }

}

I guesse the problem is that the account is passed as a seperate object parameter and so it is no longer on the context? What is the good way of doing this?

Ronald Rozema
  • 236
  • 3
  • 16
  • What is the purpose beyond this? Specifically your code error is, that you don't get values of your property, you just get property metadata. See code in this case: http://stackoverflow.com/questions/1196991/get-property-value-from-string-using-reflection-in-c-sharp – Red Dec 29 '15 at 11:35
  • @raderick I'm having problems with updating records that have a foreign key relation. It tries to insert the related objects as new with the same/existing key. I want ef to ignore the foreign relation when updating. I am using a generic repository with an update method. My code example is placed inside that update method and the entity is a generic type. I want to be able to pass along the properties on the entity that ef can ignore. – Ronald Rozema Dec 29 '15 at 12:08
  • this means, that your problem has nothing to do with your solution. Can you show the code for saving your entity, that has this issues. For me it seems, that for your foreign key relation properties you use entities, that are *not attached* to the context, so it tries to insert them again. Instead you should figure out why your FK entities are not attached, and solve this issue by loading them again or changing your repository implementation. – Red Dec 29 '15 at 12:10
  • @raderick I have editted thequestion so you can see the method that does the mutations and calls the update. – Ronald Rozema Dec 29 '15 at 12:29
  • show me your model.edmx file – Pankaj Gupta Dec 29 '15 at 12:34
  • How do you load `Account` entity that comes into this method? Do you load Addresses using `.Include(x=>x.Addresses)` method? Also error message that happens during save would be good here. – Red Dec 29 '15 at 12:35
  • @raderick I hope the post is complete enough now – Ronald Rozema Dec 29 '15 at 12:48
  • @RonaldRozema yes, it's almost clear. Now I have concerns about your `ContactMigrationHelper.MigrateIqrContactAddresses(contact);` method. What are the address entities that come from this method? Are they attached to DB? From the code I see, it's very likely these addresses are the source of the issue. – Red Dec 29 '15 at 12:55
  • @raderick public static List
    MigrateIqrContactAddresses(IReadOnlyList contact) { var address = GeocodingHelper.StringToAddress($"{contact[2]} {contact[5]} {contact[7]}"); return address != null ? new List
    {address} : null; }
    – Ronald Rozema Dec 29 '15 at 13:01
  • Can you try doing `foreach (var address in addresses) {address.Account = account; }`. It looks like Address entity does not correctly get Account PK and tries to insert Address with AccountId = 0, then receives an error because there's no Account with Id = 0 in your DB. – Red Dec 29 '15 at 13:13
  • @raderick The address does have a valid account id and still gives the same error. It is the same as the parent Account object. I thought it tried to store a new Account into the database when saving the Address with the same id as an existing account. – Ronald Rozema Dec 29 '15 at 13:29
  • I tried your code locally, and it worked fine for me. I can't see whole code for your specific action, so I can advise you to use some kind of Entity Framework Profiler to see, what kind of SQL is generated in your scenario and see what is the incorrect FK, that causes it.. – Red Dec 29 '15 at 14:16

1 Answers1

0

Allright so I have fixed the issue now by removing the Account foreign key from the Address entity because the relation is also described on the Account entity. Although it does work now I still do not fully understand why it didn't when the foreign key was present on the entity. If anyone knows the answer I would still like to know.

Ronald Rozema
  • 236
  • 3
  • 16