EF Code First Generic check Existence of an object without a common identification property?

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.

+4
source share
1 answer

How to check for availability?

As I usually saw, people who check to see if an existing entity exists check to see if its Id property is greater than zero. You should be able to use an interface with the Id property on it, or (if you expect to have objects with several key properties), you could have each object override the abstract base class by overriding the Exists property to check its own identifier properties for values ​​other than from default values. Or you can use reflection to automatically find the property or properties of the identifier, as described here .

I suspect that the rest of the problems will disappear if you correctly insert new elements, rather than trying to update them.

+1
source

Source: https://habr.com/ru/post/1392719/


All Articles