问题描述
总结
我修改了一个 nopCommerce 解决方案以包含一个具有 CodeFirst 方法的新实体,它已成功更新数据库,如下图所示。
Photo that database has table updated
当我尝试访问通过 AutoFrac 插入的存储库表时,我得到存储库返回的行,但所有列都显示空值。 注意表中的行数和在数据库表上看到的一样,所以好像已经连接了但没有显示值。
{
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
public class ProductNutrient : BaseEntity
{
public int NutrientID;
public int ProductID;
public string Nutrient;
public bool ShowLessthan;
public decimal Value;
public string Unit;
}
}
Repository 确实适用于其他表,但无论如何这里是存储库代码
/// </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;
}
这是返回完整数据还是空值?如果它仍然为空,那么您将需要检查运行时正在使用的连接字符串,因为它可能指向比您现在正在查看的更旧的数据库实例。这似乎是一个相当普遍的问题,人们使用 SSMS 或设计器来查看数据库架构,但是运行时 web/app.config 指向旧的或共享的数据库位置,或者生成的具有一些数据的数据库,但不是您期望看到的。
如果它返回您期望的数据,那么您的抽象(存储库)在某些方面存在缺陷。第一个问题是“为什么要围绕 DbContext 实现存储库?”我对存储库的建议是通用存储库,即Repository<ProductNutrient>
是一个非常糟糕的反模式。如果您是因为遇到了一个示例而正在实施存储库,则您需要了解它的根本原因。如果您正在实施存储库以“隐藏”您正在使用 EntityFramework 或隐藏 DbContext 的事实,那么恕我直言,这是实施存储库的错误原因。考虑在 EntityFramework 上实现 Repository 模式的唯一原因是使您的代码更易于单元测试。在这样做时,我强烈建议利用 IQueryable<TEntity>
作为返回类型。 .Table
可能返回 IQueryable<ProductNutrient>
,但如果它返回 DbSet<ProductNutrient>
,那么您也可能只是使用 DbContext。如果它返回类似 IEnumerable<ProductNutrient>
之类的东西,那么您可能会因为您失去 EF 可以提供的大部分功能而使您的系统面临严重的性能限制。
如果您不打算在需要模拟数据层的地方使用单元测试,以便测试获得可靠的已知状态,那么实际上没有任何理由创建存储库类,并且可能会对您的数据层施加非常昂贵的限制数据访问。我在对这个问题的回答中概述了通用存储库模式和 EF 的问题:(How to set multiple services from Entity Framework Core on Repository Pattern?) 您可以使用专用集成测试数据库映像或内存数据库,或使用 DbContext 完全测试代码更多的工作,模拟 DbContext/DbSets。对于在集成之前的开发过程中重复运行的单元测试,模拟 Repository 类要简单得多。