EF代码第一个泛型检查存在没有公共ID属性的对象

本文关键字:ID 属性 对象 第一个 代码 泛型 检查 存在 EF | 更新日期: 2023-09-27 18:21:20

编辑:此问题底部的答案

好的,我有一些通用的EF函数(其中大部分是从这里得到的),但它们似乎不起作用。

我有三个班:

 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; }
 }

我的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);
        }
    }

最后,我用以下方法调用此代码:

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;
    }

当我到达:

 user.Groups.Add(group);
 userService.Save(user);

我得到以下错误:

保存不公开其关系的外键属性的实体时出错。EntityEntries属性将返回null,因为无法将单个实体标识为异常的源。通过在实体类型中公开外键属性,可以更容易地在保存时处理异常。有关详细信息,请参阅InnerException。

以下内部异常:

INSERT语句与FOREIGN KEY约束"User_Groups_Source"冲突。冲突发生在数据库"DBNAME"、表"dbo.Users"、列"Id"中。

问题:

1) 即使实体刚刚在内存中创建,Exists也总是返回true,因此insert在Save方法中从来没有真正只调用Update,我想这是因为我不完全理解DbEntityEntry,因为它本身和Entry.entity都不为null。如何检查是否存在?

2) 即使所有代码都在TestCRUD中运行到最后,但这些实体实际上都没有保存到数据库中。我确信我的数据库设置正确,因为我的自定义Initializer总是删除和重新创建数据库,每次都插入种子数据。这可能是因为更新总是被调用,如数字1中所述。

有什么办法吗?

编辑:答案

正如假设的那样,问题是Exists总是返回true,因此从未调用insert。我通过使用反射来获得主键,并将其插入find方法来获得这样的存在:

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;
    }

所有其他方法都按预期开始发挥作用。然而,我在同一行上得到了一个不同的错误:

user.Groups.Add(group);
userService.Save(user);

是:

违反PRIMARY KEY约束"PK_GroupTypes_00551192"。无法在对象"dbo.GroupTypes"中插入重复的键。语句已终止。

我将把它作为一个新问题发布,因为这是一个新错误,但它确实解决了第一个问题。

EF代码第一个泛型检查存在没有公共ID属性的对象

如何检查是否存在?

我通常看到人们检查实体是否已经存在的方法是检查其Id属性是否大于零。您应该能够使用带有Id属性的接口,或者(如果希望实体具有多个键属性)您可以让每个实体重写一个抽象基类,重写Exists属性以检查其自己的ID属性中的非默认值。或者,您可以使用反射来自动查找ID属性,如下所述。

我怀疑,一旦你正确地插入了新项目,而不是试图更新它们,剩下的问题就会消失。