我首先使用 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);
}
}