【发布时间】:2019-02-06 11:50:33
【问题描述】:
我正在为如何正确实施存储库而苦苦挣扎。所有的数据操作都必须通过存储过程来完成(我不想争论是对是错)
在 Startup 中,我注册了 dbcontext。感谢DbQuery 和DbSet 对象,dbcontext 允许我从数据库中读取数据。
但我还需要实现我尝试过的存储库接口。但我的实现只允许我通过ExecuteSqlCommand 执行存储过程,但我无法使用DbQuery 或DBSet 对象来检索数据。
我想在一个存储库实现中使用DbQuery、DbSet 和ExecuteSqlCommand。怎么做 ?我应该在每个存储库中创建new DbContext 还是共享DbContext via dependency injection 或者存储库应该继承DbContext?
Startup.cs
services.AddDbContext<Database>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
DbContext
public class Database : DbContext
{
public Database(DbContextOptions<Database> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
public virtual DbQuery<Business> Business { get; set; }
// working
public IEnumerable<Business> GetBusiness(int id)
{
var query = @"exec query.usp_GetBusiness @id";
var p1 = new SqlParameter("@id", id);
return Business.FromSql(query, p1).ToList();
}
}
BusinessRepository.cs 我有自定义存储库,可以执行存储过程
public class BusinessRepository :IBusinessRepository
{
private readonly IHttpContextAccessor _httpAccessor;
private readonly DatabaseFacade database;
public BusinessRepository(IConfiguration configuration, IHttpContextAccessor httpAccessor)
{
DbContextOptions dbContextOptions = new DbContextOptionsBuilder()
.UseSqlServer(configuration.GetConnectionString("DefaultConnection"))
.Options;
database = new DbContext(dbContextOptions).Database;
_httpAccessor = httpAccessor;
}
// working
public void UpdateBusinessName(string Name)
{
database.ExecuteSqlCommand("exec command.usp_UpdateBusinessName @user, @name",
new SqlParameter("user", _httpAccessor.HttpContext.User.Identity.Name),
new SqlParameter("name", Name)
);
}
// this does not work, because repository does not inherit from dbContext
public virtual DbQuery<Business> Business { get; set; }
// not working, Business.FromSql(query, p1) returns ArgumentNullException !
public IEnumerable<Business> GetBusiness(int id)
{
var query = @"exec query.usp_GetBusiness @id";
var p1 = new SqlParameter("@id", id);
return Business.FromSql(query, p1).ToList();
}
}
问题底线
将所有存储库包装到某个 masterRepository 对象并调用诸如masterRepository.businessRepository.GetBusiness() 之类的存储库是个好主意吗?优点是我只能输入一个对象作为包含所有命令的参数,缺点是我创建的存储库实例我没有用于每个请求。你怎么看?
我知道这是一个复杂的问题,所以我非常感谢您的回答。
【问题讨论】:
-
"将所有存储库包装到某个 masterRepository 是否是个好主意" 不,这是一个糟糕的主意。为什么 CarRepository 依赖于 PersonRepository?存储库的唯一想法是让您能够独立地分离和测试每个部分,而您要求做的恰恰相反。此外,如果您打算使用 EF Core 来执行原始 SQL,那么使用 Dapper 会更好
-
不要传入 IHttpContextAccessor,它应该是 UpdateBusinessName 的参数。数据库可以是构造函数中的参数(假设您已将其注册到 DI),因此无需执行 DbContextOptionsBuilder 位。在某些方面,您正在与 .netcore 原则作斗争,这可能就是为什么事情并非您所期望的那样。
-
此外,正如@Neil 所说,在类中创建依赖项反对 依赖注入模式。每次手动创建一个新的上下文是对资源的巨大浪费,而且只会导致问题(让
IConfiguration对象保持长时间存活并不是一个好主意) -
感谢您的回复,所以如果我通过 DI 将
DbContext传递给构造函数,这似乎是个好主意,因为该类内部不会有依赖关系。如何使用DbQuery和DbSet对象?我虽然这个对象仅在从 DbContext 继承的类中才起作用。 @Neil 为什么将IHttpContextAccessor传递到存储库是个坏主意? -
@HenkHolterman 我在传递
IConfiguration时已经看到了足够多的内存问题。也许声明不够清楚,怪我的非母语英语:) DbContext 实例是默认作用域的,因此它们经常使用默认的AddDbContext调用来创建
标签: c# repository entity-framework-core