Reputation: 743
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.
Upvotes: 7
Views: 4369
Reputation: 31620
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);
}
}
}
Upvotes: 7
Reputation: 34299
EDIT:
I just read through the comments (i probably should have read them first but i already wrote this so ill leave it) and see you guys came to a pretty similar conclusion, hopefully this still helps explain a bit of the why. Also on a side note I think that you are better off to use the FK id property to null the relationship if its available as this means you wont have to actually load the remote entity at all.
Hey so i think this is whats going on:
You loading your Computer entity
You set the User property to null
You save changes
If this is the case as i see it there are two different ways you can make EF detect this as a change (and hence delete your relationship):
The second is far easier and should work as the user ID property isn't on a remote entity. EF will treat either a null nav property or a null FK as a change and perform a delete.
Upvotes: 1