EntityFramework 存储库,所有行 return 空值

EntityFramework repository, all rows return null values

总结

我已经修改了一个 nopCommerce 解决方案以包含一个新的实体和 CodeFirst 方法,它已经成功地更新了数据库,如下图所示。

Photo that database has table updated

当我尝试访问通过 AutoFrac 插入的存储库 table 时,我得到存储库返回的行,但所有列都显示空值。 请注意,table 中的行数与在数据库中看到的行数相同 table,因此它似乎已连接但未显示值。

Code calling Repository

{
    public partial class NutrientService : INutrientService
    {
        #region fields

        protected readonly IRepository<ProductNutrient> _productNutrientRepository;

        #endregion fields

        #region Ctor

        public NutrientService(IRepository<ProductNutrient> productNutrientRepository)
        {
            _productNutrientRepository = productNutrientRepository;
        }

        #endregion Ctor

        public IList<ProductNutrient> GetNutrients()
        {
            var query = from p in _productNutrientRepository.Table
                        select p as ProductNutrient;
            var list = query.ToList();
            return list;
        }

        public IList<ProductNutrient> GetNutrientsByProductID()
        {
           
            var query = from p in _productNutrientRepository.Table
                        select p as ProductNutrient;
            var list = query.ToList();
            return list;
        }
    }
} 

Debugging showing Null values returned from repository

Table Definition in SQL Management Studio

Entity Definition in Code

    public class ProductNutrient : BaseEntity
    {
        public int NutrientID;

        public int ProductID;

        public string Nutrient;

        public bool ShowLessThan;

        public decimal Value;

        public string Unit;
    }
}

存储库确实可以与其他 table 一起使用,但这里还是存储库代码

      /// </summary>
        public virtual IQueryable<TEntity> Table => Entities;

        /// <summary>
        /// Gets an entity set
        /// </summary>
        protected virtual ITable<TEntity> Entities => _entities ?? (_entities = _dataProvider.GetTable<TEntity>());


        #endregion
    }

我怀疑您要么迷失在抽象中,要么它们至少隐藏了一个问题。

首先剥离所有抽象,成为存储库。注入 DbContext 作为起点:

protected readonly AppDbContext _context = null;

public NutrientService(AppDbContext context)
{
    _context = context ?? throw new ArgumentNullException("context");
}

public IList<ProductNutrient> GetNutrients()
{
    var productNutrients = context.ProductNutrients
        .ToList();

    return productNutrients;
}

这个return是完整数据还是空值?如果它仍然是空的,那么您需要检查在 运行 时间使用的连接字符串,因为它可能指向比您现在正在查看的数据库实例更旧的数据库实例。这似乎是一个相当普遍的问题,人们正在使用 SSMS 或设计人员查看数据库模式,但 运行time web/app.config 指向较旧或共享的数据库位置,或数据库生成的数据包含一些数据,但不是您期望看到的数据。

如果它 return 是您期望的数据,那么您的抽象(存储库)在某些方面存在缺陷。第一个问题是“为什么要围绕 DbContext 实现存储库?”关于存储库,我的建议是通用存储库,即Repository<ProductNutrient> 是一个非常糟糕的反模式。如果您因为遇到一个示例而正在实施存储库,则需要了解它的根本原因。如果您正在实施存储库以“隐藏”您正在使用 EntityFramework 或隐藏 DbContext 的事实,那么恕我直言,这是实施存储库的错误原因。考虑在 EntityFramework 上实施 Repository 模式的唯一原因是让您的代码更容易进行单元测试。为此,我强烈建议将 IQueryable<TEntity> 用作 return 类型。 .Table 可能是 returning IQueryable<ProductNutrient>,但如果它是 returning DbSet<ProductNutrient>,那么您也可能只使用 DbContext。如果它 returning 类似 IEnumerable<ProductNutrient> 的东西,那么您可能会让您的系统在未来面临严重的性能限制,因为您失去了 EF 可以提供的大部分功能。

如果您不打算在需要模拟数据层的地方使用单元测试,以便测试获得可靠的已知状态,那么实际上没有任何理由创建存储库 classes 和可能会对您的数据访问施加非常昂贵的限制。我在对这个问题的回答中概述了通用存储库模式和 EF 的问题:() 您可以使用专用集成测试数据库映像或内存数据库,或使用 DbContext 来全面测试使用 DbContext 的代码多一点工作,嘲笑 DbContext/DbSets。对于在集成之前的开发过程中重复 运行 的单元测试,模拟存储库 class 要简单得多。