-1

Summary

I have modified a nopCommerce solution to include a new Entity with a CodeFirst Approach, it has successfully updated the Database as shown in the image below.

Photo that database has table updated

When I attempt to access the repository table, which is inserted through AutoFrac, I get rows returned by the repository but with all columns showing null values. Note that the number of rows in the table is the same as what is seen on the database table, so it seems to have been connected but not showing the values.

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;
    }
}

Repository does work with other tables, but here is the repository code anyway

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

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


        #endregion
    }
  • Please don't post code and results as images. They can't be copied (partly) for answering and their "text" won't appear in search engines. Images should only be used as a last resort. – Gert Arnold Jan 06 '21 at 21:36
  • Updated thank you. This is my first post to SO. I hope you're also able to provide some support with this issue. Thanks Dan – DanCRichards Jan 06 '21 at 21:54
  • `select p as ProductNutrient;` probably doesn't do what you think, `p` is something else. Why would you cast it anyway? But the repository isn't visible to us (esp. what's behind `_productNutrientRepository.Table`) and, still, the question can be asked without all the images. – Gert Arnold Jan 06 '21 at 22:02
  • I was wondering what is this _productNutrientRepository.Table ? Could you please show us _productNutrientRepository code and Table code? – Serge Jan 06 '21 at 22:55
  • Hey @Sergey, I have updated the post to show this. There are other services in my project that reference the repository interface and work nicely. I'm a little confused as to why the _productNutrientRepository.Table would show items in the list, but with null values. Also happens when I insert values, it just creates null records. – DanCRichards Jan 06 '21 at 23:11
  • @GertArnold You probably don't need to worry about helping me on this one, thanks though! – DanCRichards Jan 06 '21 at 23:15

1 Answers1

0

I suspect you're either getting lost within the abstractions, or they are at least concealing an issue.

Start by stripping away all of your abstractions, being the repository. Inject the DbContext instead as a starting point:

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;
}

Does this return complete data or empty values? If it is still empty then you will want to check the connection string that is being used at runtime as it's possibly pointing at an older database instance than what you are now looking at. This seems to be a fairly common problem where people are using SSMS or designers to review a DB schema, but then the runtime web/app.config is pointing to an older or shared DB location, or a DB that was generated which has some data, but not what you expect to see.

If it is returning the data you expect, then your abstraction (Repository) is flawed in some way. The first question there would be "Why are you implementing a Repository around the DbContext?" My advice when it comes to repositories is that Generic Repositories, I.e. Repository<ProductNutrient> are a very bad anti-pattern. If you are implementing a Repository because you came across an example of one, you need to understand the underlying reason for it. If you are implementing a Repository to "hide" the fact that you are using EntityFramework or hide the DbContext, then IMHO this is the wrong reason to implement a Repository. The only reason to consider implementing a Repository pattern over EntityFramework would be to make your code easier to unit test. In doing so I would highly recommend leveraging IQueryable<TEntity> as return types. It's possible that .Table is returning IQueryable<ProductNutrient>, but if it's returning DbSet<ProductNutrient> then you may as well be just using the DbContext. If it's returning something like IEnumerable<ProductNutrient> then you're potentially leaving your system open to significant performance limitations down the road as you lose most of the capabilities that EF can provide.

If you are not planning on using unit tests where you would be needing to Mock your data layer so that tests get a reliable known state then there isn't really any justification to create Repository classes and potentially impose very costly limitations on your data access. I outline the issues with the Generic Repository pattern and EF in my answer on this question: (How to set multiple services from Entity Framework Core on Repository Pattern?) You can fully test code that uses the DbContext using a dedicated integration test database image, or in-memory database, or with a bit more work, mocking the DbContext/DbSets. For unit tests which are run repeatedly during development prior to integration, mocking a Repository class is a lot simpler.

Steve Py
  • 26,149
  • 3
  • 25
  • 43
  • Thanks for your help, looking through the DBContext solved the issue. Going away from the Repo model isn't worth it, I'm working on an OpenSource framework that utilizes it, and spending time to change all of that wouldn't deliver significant value to warrant it's change. – DanCRichards Jan 07 '21 at 21:13