1

我首先使用 Entity Framework Core 2.2 代码。软删除在重写的 Context 类中实现。有一个 UnitOfWork 类为特定实体初始化存储库,同时将 Context 作为构造函数中的参数。为了更清晰的概述,本示例中省略了一些应用程序实体。我只会使用团队、成员、项目和员工。

在测试时,a 意识到:当我删除一个对象(例如,一个项目)时,它在 SaveChanges() 之后成功地将其“已删除”属性设置为“真”。但是,如果解决方案项目仍在运行,我意识到如果这个对象(Project)有一个父对象(Team),它仍然会出现在团队的 List Projects 中,即使它们的“Deleted”属性显然是“true”。当进程仍在运行时,如果我调用返回所有项目的存储库 Get() 方法,则已删除的项目不会显示在返回的项目列表中,而只会显示在团队的列表项目中。只有当我重新运行解决方案项目时,这些子对象才不再出现在父级的列表项目中。

这是我为分析问题而编写的 NUnit 测试:

[Test, Order(2)]
public void GetTeamAfterDeletingProject()
{
    //There are initially 11 projects
    var projects = unit.Projects.Get().ToList();
    Assert.AreEqual(11, projects.Count());

    Project project = unit.Projects.Get(8);
    unit.Projects.Delete(project);
    unit.Save();

    //now there are 10 projects
    projects = unit.Projects.Get().ToList();
    Assert.AreEqual(10, projects.Count());

    //this team had initially 2 projects, and one of them was deleted
    Team team = unit.Teams.Get(3);

    //only one project should be left, but there are actually two showing up - this test fails
    Assert.AreEqual(1, team.Projects.Count);

    project.Deleted = false;
    unit.Save();
}

这会干扰我在 TeamsRepository 中实现的 Delete 方法,如果列表中有子对象,则该方法不允许删除对象。这意味着,如果我想在之前的测试中删除团队,即使我删除了他所有的项目,我仍然无法在不重新启动应用程序的情况下完成(整个存储库可以在下面找到)

        public override void Delete(int id)
        {
            Team old = Get(id);

            if (old.Projects.Count != 0 || old.Members.Count != 0)
            {
                Services.ThrowChildrenPresentException();
            }

            Delete(old); 
        }

我想知道这是否是使用延迟加载时的正常行为,还是我错过了配置中的某些内容。

protected override void OnConfiguring(DbContextOptionsBuilder optionBuilder)
        {
            if(_conStr != null)
            {
                optionBuilder.UseNpgsql(_conStr);
            }
            optionBuilder.UseLazyLoadingProxies(true);
            base.OnConfiguring(optionBuilder);
        }
        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);
            builder.Entity<Member>().HasQueryFilter(x => !x.Deleted);
            builder.Entity<Employee>().HasQueryFilter(x => !x.Deleted);
            builder.Entity<Project>().HasQueryFilter(x => !x.Deleted);
            builder.Entity<Team>().HasQueryFilter(x => !x.Deleted);
        }

        public override int SaveChanges()
        {
            foreach (var entry in ChangeTracker.Entries().Where(x => x.State == EntityState.Deleted && x.Entity is BaseClass))
            {
                entry.State = EntityState.Modified;
                entry.CurrentValues["Deleted"] = true;
            }
            return base.SaveChanges();
        }

这是团队实体:

public class Team: BaseClass
    {
        public Team()
        {
            Members = new List<Member>();
            Projects = new List<Project>();
        }
        public string Name { get; set; }
        public string Description { get; set; }
        public bool StatusActive { get; set; }
        public virtual IList<Member> Members { get; set; }
        public virtual IList<Project> Projects { get; set; }
    }

    public class Member: BaseClass
    {
        public  virtual Team Team { get; set; }
        public virtual Employee Employee { get; set; }        
        public virtual Role Role { get; set; }
        public virtual MemberStatus Status { get; set; }
        public decimal HoursWeekly { get; set; }
    }

    public class BaseClass
    {
        public BaseClass()
        {
            Created = DateTime.Now;
            Creator = 0;
            Deleted = false;
        }
        [Key]
        public int Id { get; set; }
        public DateTime Created { get; set; }
        public int Creator { get; set; }
        public bool Deleted { get; set; }
    }

通用存储库和具有重写方法的特定 TeamsRepository。软删除的项目出现在 old.Projects.Count 中,所以我永远无法以这种方式删除团队(即使在

        public class Repository<Entity>: IRepository<Entity> where Entity : class
    {
        protected AppContext _context;
        protected DbSet<Entity> _dbSet;

        public Repository(AppContext context)
        {
            _context = context;
            _dbSet = _context.Set<Entity>();
        }

        public void ValidateUpdate(Entity newEntity, int id)
        {
            if (id != (newEntity as BaseClass).Id)
                throw new ArgumentException($"Error! Id of the sent object: {(newEntity as BaseClass).Id} and id in url: {id} do not match");
        }

        public virtual IQueryable<Entity> Get() => _dbSet;

        public virtual IList<Entity> Get(Func<Entity, bool> where) => Get().Where(where).ToList();

        public virtual Entity Get(int id)
        {
            Entity entity = _dbSet.Find(id);
            if (entity == null)
                throw new ArgumentException($"There is no object with id: {id} in the database");
            return entity;
        }

        public virtual void Insert(Entity entity)
        {
            entity.Build(_context);
            _dbSet.Add(entity);
        }

        public virtual void Update(Entity entity, int id)
        {
            entity.Build(_context);
            Entity old = Get(id);
            ValidateUpdate(entity, id);
            _context.Entry(old).CurrentValues.SetValues(entity);
            old.Relate(entity);
        }

        public void Delete(Entity entity) => _dbSet.Remove(entity);

        public virtual void Delete(int id)
        {
            Entity old = Get(id);
            Delete(old);
        }
    }

public class TeamsRepository: Repository<Team>
    {
        public TeamsRepository(AppContext context) : base(context) { }

        public override void Delete(int id)
        {
            Team old = Get(id);

            if (old.Projects.Count != 0 || old.Members.Count != 0)
            {
                Services.ThrowChildrenPresentException();
            }

            Delete(old); 
        }
    }
4

0 回答 0