0

I'm currently building a RestAPI using EF 6 Code First, I got a couple of models which have some relations.

I've managed to successfully add items and all that, but now I'm building a "Update"-function, which aren't going well.

I currently got this code, and it does infact update the row, but on the columns with relations it simply adds new rows instead of using the existing...

DatabaseController

public void UpdateDatabase(int id, DatabaseItem db)
    {
        using (var databasesCtx = new DatabaseContext())
        {
            DatabaseItem existing = databasesCtx.Databases.Include(a => a.Subjects).Include(a => a.Types).FirstOrDefault(d => d.Id == id);

            if(existing != null)
            {
                List<DatabaseSubject> subjects = GetAllSubjects();
                List<DatabaseType> types = GetAllTypes();

                db.Subjects = subjects.Where(s => db.Subjects.Select(b => b.Id).ToList().Contains(s.Id)).ToList();
                db.Types = types.Where(t => db.Types.Select(b => b.Id).ToList().Contains(t.Id)).ToList();

                databasesCtx.Entry(existing).CurrentValues.SetValues(db);
                databasesCtx.SaveChanges();
            }
        }
    }

DatabaseItem - Class

public class DatabaseItem
{
    public int Id { get; set; }

    public virtual ICollection<DatabaseSubject> Subjects { get; set; }

    public byte[] Icon { get; set; }

    public virtual ICollection<DatabaseType> Types { get; set; }

    public string Description { get; set; }

    [Required]
    public Boolean Public { get; set; }
}

DatabaseSubject - Class

public class DatabaseSubject
{
    public int Id { get; set; }

    public string Name { get; set; }

    public ICollection<DatabaseItem> Databases { get; set; }
}

DatabaseType - Class

public class DatabaseType
{
    public int Id { get; set; }

    public string Name { get; set; }

    public ICollection<DatabaseItem> Databases { get; set; }
}
feeloor
  • 45
  • 5

1 Answers1

1

Edit:

SetValues never updates navigation properties. When you execute your code it only knows about changes in simple / complex properties of the entity passed to your Update method. EF even don't know about related entities of the entity passed to your Update method.

You must manually tell EF about each change in your object graph

Quoted from https://stackoverflow.com/a/11710813/4834103

I left the original answer below as the above only tells why the update didn't work correctly and the answer might be helpful to rework your code

Original answer:

I think you aren't supposed to set directly

   db.Subjects = ...
   db.Types =...

Those collections are created and managed by Entity Framework.

You should remove or add elements to those collections but not overwrite them with another collection. Since those are many-to-many relations here is an example about how to update many-to-many relations in entity framework

Basically you should note what should be deleted and remove those items through the collection's interface. Note any new items that should be inserted and insert them.

Also this:

You have to load the collection (eagerly, explicitly or lazily) so that it can be tracked before setting the new values and calling save. Otherwise you will not be replacing the collection but, just be adding to it.

Check out this similar issue where I took the quote from.

Since db.Subjects or db.Types are lazy loaded they should be accessed at least once to be initialized. The provided code doesn't access them before overwriting them so they are not loaded / tracked and changeds are added as new rows

Community
  • 1
  • 1
kidroca
  • 3,480
  • 2
  • 27
  • 44