求助:这是因为我的每个服务类都有各自关联的上下文,所以我只是将上下文存储在HttpContext中,然后将DI放入存储库中

我有3节课:

 public class Group : Entity
{
    public Guid Id { get; set; }
    //other simple props
    public virtual GroupType GroupType { get; set; }

    public virtual ICollection<User> Users { get; set; }
}
 public class GroupType: Entity
{
    public Guid Id { get; set; }
    //other simple props
}

 public class User: Entity
{
    public Guid Id { get; set; }
    //other simple props

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

        _context.SaveChanges();
    }

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

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

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

    }


当我到达最后一行时:

 userService.Save(user);


我收到此错误:


  违反主键约束'PK_GroupTypes_00551192'。无法在对象“ dbo.GroupTypes”中插入重复键。
  该语句已终止。


因此,即使它已经被插入,它似乎仍在尝试插入新的groupType。

编辑:我所有的类构造函数自动将新的Guid设置为Id属性。

编辑:



我只是通过在每个对象上调用.Save()两次来运行测试,因此在上下文/ db中存在它之前以及之后都存在一次。结果似乎很奇怪:


首次在groupType对象上调用.Save():状态已分离(预期)。
第二次不带任何更改:状态未更改(预期并且证明即使我没有从上下文中查询它,更改跟踪仍在内存对象中进行)。
我第一次在组对象上调用.Save()(GroupType设置为
已保存的GroupType):组状态已分离(预期),
GroupType状态为已分离(不可预期,为什么会分离)
当我已经保存它并对其进行跟踪时在这里?)
第二次不更改:Group和GroupType统计信息均为
不变(预期)。
我第一次在用户对象上调用.Save():状态已分离
(预期)。
保存后调用user.Groups.Add(group)后第二次
组:用户未更改(预期),添加了组(预期),添加了GroupType(不期望,为什么将其标记为“已添加”,它已被保存并且应该被单独和作为组对象的一部分进行跟踪?)
最后,我尝试将groupType条目标记为未更改,并且这次对Group对象发生了相同的重复键错误,这是一致的,因为它也是已添加但不是预期的。


因此,1)为什么现有对象在添加到集合导航属性时会表现为没有被更改跟踪,但是在更简单的情况下,例如两次在group对象上调用,groupType nav prop仍然被更改跟踪并且没有添加两次,在两种情况下,我都不会重新查询以从db获取对象。

最后,2)什么是解决此问题的有效方法?我真的不想手动将nav properties实体状态设置为不变,因为我不能保证它们不会尝试添加不存在的实体,但是同时调用.Save()似乎效率很低用户.Save()中的每个组和每个组类型,或从数据库中查询每个组。

最佳答案

我敢肯定,如果您要查看数据库中的记录,它将显示一个空的guid(只有零)。要“修复”问题,您需要生成一个Guid并将其添加到您的class Id属性。解决此问题的一种简单方法是添加默认构造函数并添加Id = Guid.NewGuid();,这样您的类将具有自己的guid,并且所有内容均应按预期工作。

编辑:
由于它GroupType可以使用相同的GUId多次保存到数据库中,所以我可以想到两种情况。
1)您创建了多个组并添加了相同的GroupType,然后尝试保存。
2)您手动创建了GroupType,而不是从再次应用1)的数据库中获取它。

除非实体GroupTypeEntityStateUnchangedModified,否则它将尝试一次又一次地添加相同的GroupType。我认为您有两种选择:


保存组之前,请从数据库中获取GroupType并将其添加到您的Group实体中。
将GroupType的EntityState更改为您认为合适的状态。


EDIT2:如果要运行此命令会发生什么?

public string TestCRUD()
{
    UserService userService = UserServiceFactory.GetService();

    User user = new User("Test", "Test", "Test", "TestUser") { Groups = new Collection<Group>() };
    GroupType groupType = new GroupType("TestGroupType2", null);
    Group group = new Group("TestGroup2", null) { GroupType = groupType };

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

}


我希望它可以保存用户组添加到用户和组类型添加到组。

之所以不会因为重复而哭泣,是因为我们只调用一次userService.Save(user);。现在,如果我们想向具有相同groupType的用户添加更多Group(出于某种原因?),我们现在将不得不稍微更改代码。

public string TestCRUD()
{
    //Expecting that we use IoC or a factory to share the same DbContext on both
    //services to avoid already attached or any other weird problems
    UserService userService = UserServiceFactory.GetService();
    GroupTypeService groupTypeService = GroupTypeServiceFactory.GetService();

    GroupType groupType = new GroupType("TestGroupType", null);
    groupTypeService.Save(groupType);
    /*now if the groupType object has changed its EntityState to Unchanged
    we won't do anything, if not:
    a) get it from the db or b) set the EntityState manually */

    User user = new User("Test", "Test", "Test", "TestUser") { Groups = new Collection<Group>() };
    Group group = new Group("TestGroup", null) { GroupType = groupType };
    Group group2 = new Group("TestGroup2", null) { GroupType = groupType };

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


我希望以下代码应保存用户,保存组并使组指向相同的GroupType。

作为最后一个指针,我想强调一个事实,在任何情况下,两个服务都不应使用它们自己的DbContext,如果要跟踪实体,则它们必须共享相同的DbContext。

09-05 15:44