c# – EF Code First通用检查没有公共ID属性的对象的存在?

编辑:在这个问题的底部回答

好的,所以我有一些通用的EF功能(我从这里得到了大部分功能),但它们似乎没有用.

我有3节课:

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","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);

我收到以下错误

An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for details.

具有以下内部异常:

The INSERT statement conflicted with the FOREIGN KEY constraint “User_Groups_Source”. The conflict occurred in database “dbnAME”,table “dbo.Users”,column ‘Id’.

问题:

1)Exists总是返回true,即使实体刚刚在内存中创建,因此insert实际上永远不会被调用Save方法中的Update,我想这是因为我完全不了解DbEntityEntry因为它本身和Entry.Entity都是永远不会.我如何检查存在?

2)即使所有代码都在TestCRUD中运行直到最后,这些实体实际上都没有保存到数据库中.我很肯定我的数据库设置正确,因为我的自定义初始化程序正在丢弃并始终重新创建数据库并每次都插入种子数据.这可能是因为更新始终按照编号1中的说明进行调用.

任何想法如何解决

编辑:答案

假设,问题是存在总是返回true,因此插入从未被调用.我通过使用反射来获取主键并将其插入到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);

这是:

Violation of PRIMARY KEY constraint ‘PK_GroupTypes_00551192′. Cannot insert duplicate key in object ‘dbo.GroupTypes’.
The statement has been terminated.

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

解决方法

How can I check for an exists?

我通常看到人们检查实体是否已经存在的方式是检查其Id属性是否大于零.您应该能够使用带有Id属性的接口,或者(如果您希望实体具有多个键属性),您可以让每个实体覆盖一个抽象基类,覆盖Exists属性以检查其自己的ID属性认值.或者您可以使用反射自动查找ID属性,as explained here.

我怀疑,如果您正确插入新项目而不是尝试更新它们,其余问题将会消失.

相关文章

目录简介使用JS互操作使用ClipLazor库创建项目使用方法简单测...
目录简介快速入门安装 NuGet 包实体类User数据库类DbFactory...
本文实现一个简单的配置类,原理比较简单,适用于一些小型项...
C#中Description特性主要用于枚举和属性,方法比较简单,记录...
[TOC] # 原理简介 本文参考[C#/WPF/WinForm/程序实现软件开机...
目录简介获取 HTML 文档解析 HTML 文档测试补充:使用 CSS 选...