如何从 DbContext 中清除未插入的 POCO? - Entity Framework 代码优先
How To Clear Uninserted POCO's From DbContext? - Entity Framework Code First
我目前正在为一所大学开发一个项目,让学生创建一个帐户,他们可以使用这个帐户计算他们的 GPA、访问论坛和屏幕共享。我正在使用 ASP.NET MVC 和 ASP.NET Web Api 技术。我开发了我的业务层并制作了 "Manager" classes,这有助于为我的项目的所有 POCO 进行数据库操作。我的所有管理器 classes 使用相同的 DbContext,它来自 BaseManager class。我在我的 POCO classes 中有一些规则,如果 creedientals 是错误的,可以防止数据库插入。
当我输入错误的这些字段时,数据库插入如预期的那样失败。但是在那之后,当我插入正确的值时(将值输入到不应为 null 的字段等),数据库插入再次失败,并且尽管错误已得到纠正,但仍显示与失败尝试之前相同的验证错误。
这是我的用户 POCO class(我正在分享我正在谈论的 2 个字段):
[Table("UserTable")]
public class User
{
[Required]
[Index(IsUnique = true)]
[MaxLength(30, ErrorMessage = "Username can not exceed 30 characters!")]
public string Username { get; set; }
[Required]
[Index(IsUnique = true)]
[MaxLength(50, ErrorMessage = "Email can not exceed 50 characters!")]
[DataType(DataType.EmailAddress)]
[RegularExpression("^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3} \.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$")]
public string Email { get; set; }
}
当我检查相应 POCO class 的 DbSet 时,我看到我尝试的所有对象也都保存在本地,就像我在数据库中的 2 条记录一样。这是屏幕截图:
这是我的业务层逻辑:
- 我创建了可以由任何 POCO classes 实现的通用存储库 classes。
- 我创建了 UnitOfWork class,它使用 SingletonPattern 创建 DbSontext(UnitOfWork 对象在 UnitOfWorkBase class 处创建),并且有 2 个方法供 Manager 和 ComplexManager classes 使用。
- 1.Generic GetRepository
- 2.Generic GetManager
- 我使用管理器 classes 来定义每个 POCO 的方法集,例如 CRUD 和 POCO 指定方法(例如 UserManager 具有用于登录方法的 CheckCreedientals)。此处进行的所有数据库操作。
- 我使用复杂的管理器 classes 来实现需要多个管理器的方法。 (就像 AccountComplexManager class 中发生的 createAccount 方法创建两个 POCO classes 并将它们添加到数据库中。)。除了提交此处所做的更改外,没有任何数据库操作。正在调用相应管理器 class 的方法,并通过管理器 classes 的这些方法完成数据库操作。
- 1.Student POCO
- 2.User POCO
- 我为我的经理创建了 3 个基础 classes 以减少伪代码。
- 1.MotherBaseManager class:UnitOfWork 对象在此处创建并由进行数据库操作的所有管理器使用。这个 class 也被接下来的 2 class 继承了。它只有 Context 方法,returns UnitOfWork 对象。
- 2.BaseComplexManager class:ComplexManagers classes 的基础 class。有 GetManager 方法以获得相应的管理器来完成一些数据库任务和 Save 方法以提交对数据库的更改。
- 3.BaseManager class:经理 class 的基地 class。它有 Get Repository class 以获取相应的存储库 classes 以执行数据库操作,例如 CRUD。
我的Class业务层调整后的视图是:
我想在不重新启动应用程序的情况下从尝试插入的对象中清除 dbSet local,以便让用户有机会更正错误并重新创建帐户。
如果我在某些地方拼错或错误,请原谅我。任何帮助将不胜感激。谢谢!
除了 sellotape 关于 DbContext 生命周期的非常有效的评论之外,您还可以做几件事。
如果您想对您的应用进行最少的更改,那么我建议您使用交易,例如
using (var transaction = dbContext.Database.BeginTransaction())
{
try
{
// Prepare POCOs to be stored
...
dbContext.SaveChanges();
transaction.Commit();
}
catch (Exception)
{
// Handle failure
}
}
如果SaveChanges()
失败,您的交易将自动回滚,所有添加到该区块的对象将从dbContext
移除。
您可以在 MSDN 中找到有关 EF Core or EF 6 中事务的更多信息。
但是,我建议您重新考虑您的验证方案。数据验证不应该发生在数据库级别 - 验证应该在请求生命周期的早期发生,甚至可能在您创建要存储到数据库的 POCO 之前。
我目前正在为一所大学开发一个项目,让学生创建一个帐户,他们可以使用这个帐户计算他们的 GPA、访问论坛和屏幕共享。我正在使用 ASP.NET MVC 和 ASP.NET Web Api 技术。我开发了我的业务层并制作了 "Manager" classes,这有助于为我的项目的所有 POCO 进行数据库操作。我的所有管理器 classes 使用相同的 DbContext,它来自 BaseManager class。我在我的 POCO classes 中有一些规则,如果 creedientals 是错误的,可以防止数据库插入。
当我输入错误的这些字段时,数据库插入如预期的那样失败。但是在那之后,当我插入正确的值时(将值输入到不应为 null 的字段等),数据库插入再次失败,并且尽管错误已得到纠正,但仍显示与失败尝试之前相同的验证错误。
这是我的用户 POCO class(我正在分享我正在谈论的 2 个字段):
[Table("UserTable")]
public class User
{
[Required]
[Index(IsUnique = true)]
[MaxLength(30, ErrorMessage = "Username can not exceed 30 characters!")]
public string Username { get; set; }
[Required]
[Index(IsUnique = true)]
[MaxLength(50, ErrorMessage = "Email can not exceed 50 characters!")]
[DataType(DataType.EmailAddress)]
[RegularExpression("^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3} \.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$")]
public string Email { get; set; }
}
当我检查相应 POCO class 的 DbSet 时,我看到我尝试的所有对象也都保存在本地,就像我在数据库中的 2 条记录一样。这是屏幕截图:
这是我的业务层逻辑:
- 我创建了可以由任何 POCO classes 实现的通用存储库 classes。
- 我创建了 UnitOfWork class,它使用 SingletonPattern 创建 DbSontext(UnitOfWork 对象在 UnitOfWorkBase class 处创建),并且有 2 个方法供 Manager 和 ComplexManager classes 使用。
- 1.Generic GetRepository
- 2.Generic GetManager
- 我使用管理器 classes 来定义每个 POCO 的方法集,例如 CRUD 和 POCO 指定方法(例如 UserManager 具有用于登录方法的 CheckCreedientals)。此处进行的所有数据库操作。
- 我使用复杂的管理器 classes 来实现需要多个管理器的方法。 (就像 AccountComplexManager class 中发生的 createAccount 方法创建两个 POCO classes 并将它们添加到数据库中。)。除了提交此处所做的更改外,没有任何数据库操作。正在调用相应管理器 class 的方法,并通过管理器 classes 的这些方法完成数据库操作。
- 1.Student POCO
- 2.User POCO
- 我为我的经理创建了 3 个基础 classes 以减少伪代码。
- 1.MotherBaseManager class:UnitOfWork 对象在此处创建并由进行数据库操作的所有管理器使用。这个 class 也被接下来的 2 class 继承了。它只有 Context 方法,returns UnitOfWork 对象。
- 2.BaseComplexManager class:ComplexManagers classes 的基础 class。有 GetManager 方法以获得相应的管理器来完成一些数据库任务和 Save 方法以提交对数据库的更改。
- 3.BaseManager class:经理 class 的基地 class。它有 Get Repository class 以获取相应的存储库 classes 以执行数据库操作,例如 CRUD。
我的Class业务层调整后的视图是:
我想在不重新启动应用程序的情况下从尝试插入的对象中清除 dbSet local,以便让用户有机会更正错误并重新创建帐户。
如果我在某些地方拼错或错误,请原谅我。任何帮助将不胜感激。谢谢!
除了 sellotape 关于 DbContext 生命周期的非常有效的评论之外,您还可以做几件事。
如果您想对您的应用进行最少的更改,那么我建议您使用交易,例如
using (var transaction = dbContext.Database.BeginTransaction())
{
try
{
// Prepare POCOs to be stored
...
dbContext.SaveChanges();
transaction.Commit();
}
catch (Exception)
{
// Handle failure
}
}
如果SaveChanges()
失败,您的交易将自动回滚,所有添加到该区块的对象将从dbContext
移除。
您可以在 MSDN 中找到有关 EF Core or EF 6 中事务的更多信息。
但是,我建议您重新考虑您的验证方案。数据验证不应该发生在数据库级别 - 验证应该在请求生命周期的早期发生,甚至可能在您创建要存储到数据库的 POCO 之前。