Reputation: 1958
i was working with Entity framework version 6.1.3 and found an unexpected behaviour, so i have created a small code that can reproduce it
when i execute below code, and see in database vehicle's userid is set to previously inserted user. it should throw exception related to referential integrity
class Program
{
private static void Main(string[] args)
{
using (MyDbContext dbContext = new MyDbContext())
{
dbContext.Users.Add(new User { Email = "[email protected]", Name = "x" });
dbContext.Vehicles.Add(new Vehicle { BuildYear = 2016, Model = "BMW X4" });
dbContext.SaveChanges();
}
}
}
class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public virtual ICollection<Vehicle> Vehicles { get; set; }
}
class Vehicle
{
public int Id { get; set; }
public int UserId { get; set; }
public string Model { get; set; }
public int BuildYear { get; set; }
public virtual User User { get; set; }
}
class MyDbContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Vehicle> Vehicles { get; set; }
}
EDIT
i am using code first approach. when i see result in database, userid in vehicle table is last inserted user id. there is no triggers in database AFAIK
this is what i am seeing in SSMS
Upvotes: 2
Views: 110
Reputation: 109080
Here's what happens:
dbContext.Users.Add(new User { Email = "[email protected]", Name = "x" });
A User
object has been created having Id = 0
.
dbContext.Vehicles.Add(new Vehicle { BuildYear = 2016, Model = "BMW X4" });
A Vehicle
has been created, having UserId = 0
.
Because of the identical key values, EF considers both objects as connected.
When SaveChanges
runs, EF executes relationship fixup by which it populates Vehicle.User
and sets Vehicle.UserId
to the new user's Id value, which it obtained from the database.
You correctly expected a referential constraint to be violated, as UserId
can't be null
and you don't seem to set it. The only way you can fix this is by setting the Vehicle
's User
property. You can't set Vehicle.UserId
because the User
's Id isn't known yet:
var user = new User { Email = "[email protected]", Name = "x" };
dbContext.Users.Add(user);
dbContext.Vehicles.Add(new Vehicle { BuildYear = 2016, Model = "BMW X4", User = user });
(By the way, I was side-tracked by the phrase previously inserted user, which suggested EF connected a user you inserted before running your code).
Upvotes: 2
Reputation: 6491
It's an EF behaviour.
Vehicle.Id and User.Id are generated as autonumbering fields.
Vehicle.UserId is the field that is associated by default to the id of the Vehicle.User relationship.
With your classes, if you don't set Vehicle.User you also must have added one and only one User in the context that will be associated with the vehicle otherwise you will receive an exception.
If you change the UserId to optional the behaviour changes as expected and the user is not automatically associated but it will be Always the same as Vehicle.User.Id
Upvotes: 1
Reputation: 151588
I cannot find it documented anywhere, but apparently because there's a required relationship between vehicle and user, and you add both in one batch, Entity Framework decides that they must belong together, instead of executing the specified queries and letting the database return a referential constraint error.
I can't say I like this.
The solution, as you commented that you want this relation to be optional, is to make the UserId
of type int?
. Then the described behavior will not occur.
Upvotes: 1
Reputation: 14488
You're not filling in the UserId
property, so that property will be 0
by default value. Your User
(I assume it's the first user you insert as it's testcode) will get Id = 0
from the database too. So when you save them both, Vehicle
will have a foreign key relationship with your first User
.
What you're doing is not correct by the way. If your Vehicle
navigation property can be null, you should make the corresponding foreign key Nullable
too. Otherwise you have to assign a User
to every new Vehicle
you create.
Upvotes: 1