audi1m
audi1m

Reputation: 3

Nullable reference type when using DTO classes

Product

        public int Id { get; set; }
        public string ProductName { get; set; }
        public string ProductDescription { get; set; }
        public Category Category {get; set;}

Category

        public int Id { get; set; }
        public string CategoryName { get; set; }
        public string CategoryDescription { get; set; }
        public Product Product{get; set;}

ProductViewModel

    public int Id { get; set; }
    public string ProductName { get; set; }
    public string ProductDescription { get; set; }
    public Category Category {get; set;}

Controller

     public IActionResult GetProducts()
     {
        using var dbContext = new DatabaseContext();
        var result = dbContext.Products.Where(i => i.Id == id)
                                 .ThenInclude(i => i.Category)
                                 .ToList();
        List<ProductViewModel> productList = new List<ProductViewModel>();
        foreach(var item in result)
        {
         var model = ProductViewModel()
         {
             Id = item.Id,
             ProductName = item.ProductName,
             ProductDescription = item.ProductDescription,
             Category = new Category()
             { 

             // Error: item.Category.CategoryName = 'item.Category.CategoryName' threw an 
                 exception of type 'System.NullReferenceException'

             CategoryName= item.Category.CategoryName, 
             CategoryDescription = item.Category.CategoryDescription, 
             Id = item.Category.Id 
             }
          productList.Add(model); 
         }
     }

How can I ignore null values in my DTO class.

I get my products from database. Since the category is null in some products, I get an error when mapping it to my DTO class.

Upvotes: 0

Views: 849

Answers (3)

Darkk L
Darkk L

Reputation: 1035

Hello you can try using ??= operator which can protects you from null reference exception

using var dbContext = new A1APPsContext();
            var result = dbContext.Products.Where(i => i.Id == id)
                .Include(i => i.Category)
                .ToList();

            List<ProductViewModel> productList = new List<ProductViewModel>();
            foreach (var item in result)
            {
                item.Category ??= new Category();
                var model = new ProductViewModel()
                {
                    Id = item.Id,
                    ProductName = item.ProductName,
                    ProductDescription = item.ProductDescription,
                    Category = new Category()
                    {
                        CategoryName = item.Category.CategoryName,
                        CategoryDescription = item.Category.CategoryDescription,
                        Id = item.Category.Id
                    }
                };
                productList.Add(model);
            }

In that case you can also give a "No Category" category name and you will get it only when you dont have category by applying it in the class

public class Category
        {
            public int Id { get; set; }
            public string CategoryName { get; set; } = "No Category";
            public string CategoryDescription { get; set; }
            public Product Product { get; set; }
        }

Upvotes: 0

Dominik
Dominik

Reputation: 299

Answer of @Svyatoslav Danyliv is the clean solution to your problem! However below my guess to your exception in your current solution.

I think it is because you are using ThenInclude. ThenInclude is usually used when you need to go into deeper includes.

Example: human --> head --> eye

dbContext.Humans.Include(x => x.Head).ThenInclude(x => x.Eye);

Your adjusted code:

var result = dbContext.Products.Include(i => i.Category).Where(i => i.Id == id).ToList();

Change ThenInclude with Include and give it a try! :)

Upvotes: 0

Svyatoslav Danyliv
Svyatoslav Danyliv

Reputation: 27282

Use Select for projecting Model to DTO. It will create optimal SQL and should avoid loading unwanted data into the memory. Also EF should resolve nullability automatically.

public IActionResult GetProducts()
{
    using var dbContext = new DatabaseContext();

    var productList = dbContext.Products
        .Where(i => i.Id == id)
        .Select(item => new ProductViewModel
        {
            Id = item.Id,
            ProductName = item.ProductName,
            ProductDescription = item.ProductDescription,
            Category = new Category
            { 
                CategoryName = item.Category.CategoryName, 
                CategoryDescription = item.Category.CategoryDescription, 
                Id = item.Category.Id 
            }
        })
        .ToList();
    ...
}

Upvotes: 1

Related Questions