【问题标题】:.net core 2 how to implement repository properly.net core 2 如何正确实现存储库
【发布时间】:2019-02-06 11:50:33
【问题描述】:

我正在为如何正确实施存储库而苦苦挣扎。所有的数据操作都必须通过存储过程来完成(我不想争论是对是错)

在 Startup 中,我注册了 dbcontext。感谢DbQueryDbSet 对象,dbcontext 允许我从数据库中读取数据。

但我还需要实现我尝试过的存储库接口。但我的实现只允许我通过ExecuteSqlCommand 执行存储过程,但我无法使用DbQueryDBSet 对象来检索数据。

我想在一个存储库实现中使用DbQueryDbSetExecuteSqlCommand。怎么做 ?我应该在每个存储库中创建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 传递给构造函数,这似乎是个好主意,因为该类内部不会有依赖关系。如何使用 DbQueryDbSet 对象?我虽然这个对象仅在从 DbContext 继承的类中才起作用。 @Neil 为什么将IHttpContextAccessor 传递到存储库是个坏主意?
  • @HenkHolterman 我在传递IConfiguration 时已经看到了足够多的内存问题。也许声明不够清楚,怪我的非母语英语:) DbContext 实例是默认作用域的,因此它们经常使用默认的AddDbContext 调用来创建

标签: c# repository entity-framework-core


【解决方案1】:

我听从了 cmets 的建议,这是我针对我的场景的第一个可行解决方案。这可能不是最佳实践,但至少它是有效的。

Startup.cs

services.AddDbContext<AppContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

DbContext

public class AppContext : DbContext
    {
        public AppContext (DbContextOptions<AppContext> options) : base(options)
        {
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
        }
        public virtual DbQuery<Business> Business { get; set; }

    }

BusinessRepository.cs

 public class BusinessRepository :IBusinessRepository
    {
        private readonly AppContext _context;

        public BusinessRepository(AppContext context)
        {
            _context = context;
        }

        // working
        public IEnumerable<Business> GetBusiness(int id)
        {
             var query = @"exec query.usp_GetBusiness @id";
             var p1 = new SqlParameter("@id", id);
             return _context.Business.FromSql(query, p1).ToList();
        }

        // working
        public void UpdateBusinessName(string name, string user)
        {
            _context.Database.ExecuteSqlCommand("exec command.usp_UpdateBusinessName @user, @name",
                new SqlParameter("user", user),
                new SqlParameter("name", name)
            );
        }
}

【讨论】:

    猜你喜欢
    • 2022-10-18
    • 1970-01-01
    • 2021-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-14
    • 1970-01-01
    相关资源
    最近更新 更多