Search code examples
c#entity-frameworkasp.net-corerazor-pages

EF foreign key is NULL


I have the following model class:

[key]
public int CustomerId { get; set; }
public string CustomerName { get; set; }
[ForeignKey("CustomerType")]
public int? CustomerTypeId { get; set; }
public virtual CustomerType CustomerType { get; set; }

[Key]
public int CustomerTypeId { get; set; }
public string CustomerTypeCode { get; set; }

Then I want to load it into a view with this controller code:

public async Task<IActionResult> Index()
{
     var obj = _db.Customer.Include(i => i.CustomerType);
     return View(await obj.ToListAsync());
}

On the view:

@using IEnumerable<myProject.Models.Customer>
<table>
<thead>
   <tr>
     <th>Customer
     <th>CustomerType
   </tr>
</thead>
<tbody>
   @foreach (var item in Model)
   {
   <tr>
     <td>@item.Customer</td>
     <td>@item.CustomerType.Code</td>
   </tr>
   }
</tbody>
</table>

When I tried to run it, I get an error for @item.CustomerType.Code because the data is null in the database:

System.NullReferenceException: 'Object reference not set to an instance of an object.'

Does anyone know why? Even I tried to put ? on the model, it doesn't work.

Thanks a lot.


Solution

  • Well keeping all the existing code I found this solution for you. Just need to change a bit on your view. No changes on controller.

    Models:

    public class Customer
        {
            [key]
            public int CustomerId { get; set; }
            public string CustomerName { get; set; }
            [ForeignKey("CustomerType")]
            public int? CustomerTypeId { get; set; }
            public virtual CustomerType CustomerType { get; set; }
        }
    
    public class CustomerType
        {
            [Key]
            public int CustomerTypeId { get; set; }
            public string CustomerTypeCode { get; set; }
          
        }
    

    Controller:

      public async Task<IActionResult> CustomerIndex()
            {
                var obj = _context.Customers.Include(i => i.CustomerType);
                return View(await obj.ToListAsync());
            }
    

    View:

    @model IEnumerable<MVCApps.Models.Customer>
    <table class="table table table-bordered">
        <thead>
            <tr>
                <th>Customer
                <th>Customer Type
            </tr>
        </thead>
        <tbody>
            @foreach (var item in Model)
            {
                <tr>
                    <td>@item.CustomerName</td>
                    <td>@(item.CustomerType == null ? "" : item.CustomerType.CustomerTypeCode)</td>
                </tr>
            }
        </tbody>
    </table>
    

    Note: There are few other way to handle this scenario from controller side but this one I think more less code and easiest way. <td>@item.CustomerType?.CustomerTypeCode</td> this also would work but I prefer to use ternary operator here

    Output:

    enter image description here

    Hope it would help you.