EDIT: ANSWER TO THIS QUESTION NUMBER
Ok, so I have some common EF features (most of which I got from here), but they don't seem to work.
I have 3 classes:
public class Group : Entity { public Guid Id { get; set; } public string Name { get; set; } public string Description { get; set; } public virtual GroupType GroupType { get; set; } public virtual ICollection<User> Users { get; set; } } public class GroupType: Entity { public Guid Id { get; set; } public string Name { get; set; } public string Description { get; set; } } public class User: Entity { public Guid Id { get; set; } public string FirstName { get; set; } public string MiddleName { get; set; } public string LastName { get; set; } public string UserName { get; set; } public virtual ICollection<Group> Groups { get; set; } }
My operations with CRUD:
public void Insert(TClass entity) { if (_context.Entry(entity).State == EntityState.Detached) { _context.Set<TClass>().Attach(entity); } _context.Set<TClass>().Add(entity); _context.SaveChanges(); } public void Update(TClass entity) { DbEntityEntry<TClass> oldEntry = _context.Entry(entity); if (oldEntry.State == EntityState.Detached) { _context.Set<TClass>().Attach(oldEntry.Entity); } oldEntry.CurrentValues.SetValues(entity); //oldEntry.State = EntityState.Modified; _context.SaveChanges(); } public bool Exists(TClass entity) { bool exists = false; if(entity != null) { DbEntityEntry<TClass> entry = _repository.GetDbEntry(entity); exists = entry != null; } return exists; } public void Save(TClass entity) { if (entity != null) { if (Exists(entity)) _repository.Update(entity); else _repository.Insert(entity); } }
Finally, I call this code in the following way:
public string TestCRUD() { UserService userService = UserServiceFactory.GetService(); User user = new User("Test", "Test", "Test", "TestUser") { Groups = new Collection<Group>() }; userService.Save(user); User testUser = userService.GetOne(x => x.UserName == "TestUser"); GroupTypeService groupTypeService = GroupTypeServiceFactory.GetService(); GroupType groupType = new GroupType("TestGroupType2", null); groupTypeService.Save(groupType); GroupService groupService = GroupServiceFactory.GetService(); Group group = new Group("TestGroup2", null) { GroupType = groupType }; groupService.Save(group); user.Groups.Add(group); userService.Save(user); return output; }
When will I get to:
user.Groups.Add(group); userService.Save(user);
I get the following error:
An error occurred while saving objects that do not display foreign key properties for their relationships. The EntityEntries property will return null because a single object cannot be identified as an exception source. Saving exception handling can be simplified by displaying foreign key properties in your object types. See InnerException for more details.
With the following internal exception:
The INSERT statement was against the FOREIGN KEY "User_Groups_Source" restrictions. The conflict occurred in the database "DBNAME", the table "dbo.Users", in the column "Id".
Problems:
1) Exists always returns true, even if the object was just created in memory, and therefore the insert is never called only by the Update inside the Save method, I think this is because I do not understand DbEntityEntry completely because both myself and Entry. Entity is never null. How to check for availability?
2) Despite the fact that all the code runs in TestCRUD to the very end, none of these objects are actually stored in the database. I am sure that I have set up my database correctly, because my custom Initializer always discards and re-creates the database and each time enters the seed data. This is probably because the update is always called as indicated in number 1.
Any ideas how to fix it?
EDIT: ANSWER
The problem was supposed to be that Exists always returned true, so the insert was never called. I fixed this using reflection to get the primary key and paste it into the find method so that it appears:
public bool Exists(TClass entity) { bool exists = false; PropertyInfo info = entity.GetType().GetProperty(GetKeyName()); if (_context.Set<TClass>().Find(info.GetValue(entity, null)) != null) exists = true; return exists; }
All other methods began to work as expected. However, I have another error on the same line:
user.Groups.Add(group); userService.Save(user);
which was:
Violation of PRIMARY KEY constraint 'PK_GroupTypes_00551192'. Cannot insert duplicate key into object "dbo.GroupTypes". Application completed.
I will post this as a new question, as this is a new bug, but it solved the first problem.