Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Removing a navigation property doesn't update the database

I have 2 POCO classes (below) and wish to remove the link between two of their records. According to this EF 5.0 should be able to handle the removal without loading the User class like so:

context.Computers.Find("test").User = null;
context.SaveChanges();

This doesn't work, but using the .net 4 approved method it works:

en = context.Computers.Find("test");
context.Entry(en).Reference(e => e.User).Load();
en.User = null;
context.SaveChanges();

My EF reference is EntityFramework.dll version 5.0.0.0. Am I missing something obvious here?

Here are the classes:

public class Computer
{
    public string Id { get; set; }
    public Nullable<int> UserId { get; set; }
    public virtual User User { get; set; }
}
public class User
{
    public int Id { get; set; }
    public virtual ICollection<Computer> Computers { get; set; }
}

Edit: Here is the specific lines in the above linked article that don't seem to agree with the functionality I'm seeing:

To delete the relationship, set the navigation property to null. If you are working with the Entity Framework that is based on .NET 4.0, then the related end needs to be loaded before you set it to null. For example:

context.Entry(course).Reference(c => c.Department).Load();
course.Department = null;

Starting with the Entity Framework 5.0, that is based on .NET 4.5, you can set the relationship to null without loading the related end.

like image 864
Jake Avatar asked Jan 24 '13 19:01

Jake


1 Answers

You don't see the relationship being deleted since your proxy is not a change tracking proxy but lazy loading proxy only. To make it a change tracking proxy you need to set all the properties to be virtual. Below please find an example that resets a navigation property without loading it first. Now a question is whether or not to use change tracking proxies - see this post as it contains an interesting discussion on this.

public class Computer
{
    public virtual string Id { get; set; }
    public virtual Nullable<int> UserId { get; set; }
    public virtual User User { get; set; }
}

public class User
{
    public int Id { get; set; }
    public virtual ICollection<Computer> Computers { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<Computer> Computers { get; set; }
    public DbSet<User> Users { get; set; } 
}

class Program
{
    static void Main(string[] args)
    {
        using (var ctx = new MyContext())
        {
            if (!ctx.Computers.Any())
            {
                var user = ctx.Users.Add(new User());
                ctx.Computers.Add(new Computer() { Id = "MyComputer", User = user });
                ctx.SaveChanges();
            }
        }

        using (var ctx = new MyContext())
        {
            var computer = ctx.Computers.Single();
            computer.User = null;
            ctx.SaveChanges();
        }

        using (var ctx = new MyContext())
        {
            var computer = ctx.Computers.Include("User").Single();
            Console.WriteLine(computer.User == null);
        }
    }
}
like image 139
Pawel Avatar answered Oct 10 '22 07:10

Pawel