public partial class MyDbContext : DbContext
{
public MyDbContext()
: base("name=Model1")
{
}
public virtual DbSet<User> Users { get; set; }
public virtual DbSet<UserGroup> UserGroups { get; set; }
public virtual DbSet<UserGroupMember> UserGroupMembers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder) { }
}
[Table("gnr.UserGroup")]
public partial class UserGroup
{
public UserGroup()
{
ChildUserGroups = new HashSet<UserGroupMember>();
UserGroupMembers = new HashSet<UserGroupMember>();
}
public long ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
[InverseProperty("ChildUserGroup")]
public virtual ICollection<UserGroupMember> ChildUserGroupMembers { get; set; }
[InverseProperty("UserGroup")]
public virtual ICollection<UserGroupMember> UserGroupMembers { get; set; }
}
[Table("gnr.UserGroupMember")]
public partial class UserGroupMember
{
public long ID { get; set; }
public long? UserID { get; set; }
public virtual User User { get; set; }
[ForeignKey("UserGroup")]
public long UserGroupID { get; set; }
public virtual UserGroup UserGroup { get; set; }
[ForeignKey("ChildUserGroup")]
public long? ChildUserGroupID { get; set; }
public virtual UserGroup ChildUserGroup { get; set; }
}
[Table("gnr.User")]
public partial class User
{
public User()
{
UserGroupMembers = new HashSet<UserGroupMember>();
}
public long ID { get; set; }
public string Username { get; set; }
public string MobileNumber { get; set; }
public virtual ICollection<UserGroupMember> UserGroupMembers { get; set; }
}
static void Main(string[] args)
{
WorkNotCorrectly();
Console.WriteLine("Done");
Console.ReadLine();
}
private static void WorkNotCorrectly()
{
using (var db = new MyDbContext())
{
var ug = new UserGroup { Title = "It's a new UserGroup 1" };
var cugm = new UserGroupMember { ChildUserGroupID = 1 };
ug.ChildUserGroupMembers.Add(cugm);
// After This Line
db.UserGroups.Add(ug);
The MyDbContext sets the 'ChildUserGroup' property of the 'cugm' object to the 'ug'
But the expected behaviour is to set the 'UserGroup' property of 'cugm' object to the 'ug'
'ug' object To Json:
{
"ID": 0,
"Title": "It's a new UserGroup 1",
"Description": null,
"ChildUserGroupMembers": [
{
"ID": 0,
"UserID": null,
"User": null,
"UserGroupID": 0,
"UserGroup": null,
"ChildUserGroup": HERE IS THE PROBLEM => The MyDbContext sets the 'ChildUserGroup' property instead of 'UserGroup' property,
"ChildUserGroupID": 1
}
],
"UserGroupMembers": []
}
And the SaveChanges:
db.SaveChanges();
}
}
'ug' object To Json After SaveChanges:
{
"ID": 2,
"Title": "It's a new UserGroup 1",
"Description": null,
"ChildUserGroupMembers": [
{
"ID": 1,
"UserID": null,
"User": null,
"UserGroupID": 2,
"ChildUserGroupID": 2 WHAT???? IT IS CHANGED TO 2 ( THE NEW UserGroup THAT IS GENERATED),
"ChildUserGroup": HERE IS THE PROBLEM => The MyDbContext sets the 'ChildUserGroup' property instead of 'UserGroup' property
}
],
????? WHAT IS THIS??? WHY UserGroupMembers PROPERTY IS FILLED
"UserGroupMembers": [
{
"ID": 1,
"UserID": null,
"User": null,
"UserGroupID": 2,
"ChildUserGroupID": 2
}
]
}
The Expected behavior and result is :
{
"ID": 2,
"Title": "It's a new UserGroup 1",
"Description": null,
"ChildUserGroupMembers": [
{
"ID": 1,
"UserID": null,
"User": null,
"UserGroupID": 2,
"UserGroup": 'The ug object with ID of 2 ',
"ChildUserGroupID": 1
}
]
}
Result in SSMS and the relationship diagram
It seems that the EF confused to identify the correct FK,The one which has to fill by itself after inserting the object and the one that is filled by me??!!
Update: This is the relation between entities:
UserGroupMember is a bridge table between UserGroup and User
Each User can be member of 1...* UserGroup
Each UserGroup can have 1...* User as member
(until here its like a normal bridge table to represent a many to many relationship)
4. Each UserGroup can have 1...* ChildUserGroup as a member
(this means that a UserGroup can have a User or a ChildUserGroup as member, something like 'Users and Groups' of Windows)
Sincerely.
The main issue here, your code is setting incorrect navigation properties than what you are expecting.
First you are using InverseProperty
attributes to define your relationships.
UserGroup.ChildUserGroupMembers
& UserGroupMember.ChildUserGroup
constitute one relationship with foreign key property as ChildUserGroupID
UserGroup.UserGroupMembers
& UserGroupMember.UserGroup
constitute another relationship with foreign key property as UserGroupID
In EF when you define a relationship, there are 3 components, principal to dependent navigation, dependent to principal navigation & foreign key property. Setting value of any one of them would determine others too. If you set any navigation then foreign key property will be set to have same value as principal key property. Navigations also get populated if they are already loaded in memory.
You already have data in your UserGroup table with ID = 1 as SSMS output shows. Now in your code,
UserGroup
ug
. UserGroupMember
cugm
. cugm.ChildUserGroupID
= 1. Given relationship the entity has, cugm.ChildUserGroup
navigation (which is associated with ChildUserGroupID
fk), should have UserGroup
with ID = 1 assigned to it. Since it is not loaded in memory, that navigation will remain null. Same way if the UserGroup
with ID = 1 was loaded in memory than UserGroup.ChildUserGroupMembers
collection would add cugm
to it. cugm
to ug.ChildUserGroupMembers
collection. Meaning the FK property cugm.ChildUserGroupID
should take value of ug.ID
. And cugm.ChildUserGroup
which is inverse navigation should point to ug
. Since till this point EF not in picture, none of above changes will happen till entity is added. ug
to UserGroups
db set so EF will start tracking the entity and its children. Since ug.ChildUserGroupMembers
collection have cugm
added to it, EF will set cugm.ChildUserGroup
to ug
. ug
object still have temporary key hence EF will not copy ug.ID
to cugm.ChildUserGroupID
That is how you got your first JSON. It has ChildUserGroup
set because you set the inverse navigation of it.
Once you call SaveChanges, EF will save the entity ug
to database. Since your database already have Entity with ID = 1, it gets next ID which is 2. Since ug.ID
is not temporary value anymore, cugm.ChildUserGroupID
will take its value and change to 2
.
Now based on your SSMS data, you want to create new UserGroup
object - ug
which would get ID = 2 when saved. You want to create new UserGroupMember
object - cugm
which would get ID = 1 (first row with identity column.) cugm.UserGroupId
= 2 so cugm.UserGroup
navigation should be set to ug
& cugm.ChildUserGroupID
= 1.
This is what code should look like
var ug = new UserGroup { Title = "It's a new UserGroup 1" };
var cugm = new UserGroupMember { ChildUserGroupID = 1 };
ug.UserGroupMembers.Add(cugm); // You want to set UserGroupID = 2 so cugm should be added to its corresponding inverse navigation
db.UserGroups.Add(ug);
db.SaveChanges();
Above code will generate exact record as you want in your database.
The JSON output of ug
object will be like below (which is also incorrect in your question)
{
"ID": 2,
"Title": "It's a new UserGroup 1",
"Description": null,
"UserGroupMembers": [{
"ID": 1,
"UserID": null,
"User": null,
"UserGroupID": 2,
"UserGroup": ... // Pointing to UserGroup with ID = 2
"ChildUserGroupID": 1,
"ChildUserGroup": null
}]
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.