locked
Model navigation property returns null value in my asp.net core project. RRS feed

  • Question

  • User-79977429 posted

    Hi

    I have some entities like Patients with some relations to another entities. My problem is that, in Details view, the navigation properties (which points to other tables) does not display anything! apparently it returns null.

    after a lot of search, some people says i should change some configation options in my dbContext (see this link), but i could not find Configuration property!

    some people says Lazy loading is not supported by ef core, i should include it manually in my linq query (see this link), but also i could not find Include in my dbContext!!

    Here is my Patients class :

    public partial class Patients
    {
            [Key]
            public Guid PatientRowID { get; set; }
            [Required]
            [StringLength(50)]
            public string PatientCaseID { get; set; }
            [StringLength(50)]
            public string PatientFname { get; set; }
            [StringLength(50)]
            public string PatientLname { get; set; }
    	public int? SexID { get; set; }
    	[ForeignKey(nameof(SexID))]
            [InverseProperty("Patients")]
            public virtual Sex Sex { get; set; }
    }

    And here is my another table (Sex) :

    public partial class Sex
    {
            public Sex()
            {
                Patients = new HashSet<Patients>();
                Persons = new HashSet<Persons>();
            }
    
            [Key]
            public int SexID { get; set; }
            [StringLength(50)]
            public string SexName { get; set; }
    
            [InverseProperty("Sex")]
            public virtual ICollection<Patients> Patients { get; set; }
            [InverseProperty("Sex")]
            public virtual ICollection<Persons> Persons { get; set; }
    }

    And here is my action method :

    public IActionResult Details(string id)
            {
                if (string.IsNullOrEmpty(id))
                    return BadRequest();
    
                Guid gid = Guid.Parse(id);
                var patient = _dbContext.Patients.Where(p => p.PatientRowID == gid).FirstOrDefault();
                if (patient == null)
                    return NotFound();
    
                return View(patient);
            }

    And here is my Details view code :

    <div>
    <dl class="row">
            <dt class = "col-sm-2">
                @Html.DisplayNameFor(model => model.PatientCaseID)
            </dt>
            <dd class = "col-sm-10">
                @Html.DisplayFor(model => model.PatientCaseID)
            </dd>
            <dt class = "col-sm-2">
                @Html.DisplayNameFor(model => model.PatientFname)
            </dt>
            <dd class = "col-sm-10">
                @Html.DisplayFor(model => model.PatientFname)
            </dd>
            <dt class = "col-sm-2">
                @Html.DisplayNameFor(model => model.PatientLname)
            </dt>
            <dd class = "col-sm-10">
                @Html.DisplayFor(model => model.PatientLname)
            </dd>
    	<dt class = "col-sm-2">
                @Html.DisplayNameFor(model => model.SexID)
            </dt>
            <dd class = "col-sm-10">
                @Html.DisplayFor(model => model.Sex.SexName) // display nothing!
            </dd>
    </dl>
    </div>

    Can anybody help me where is my problem & how to solve it?

    Thanks in advance

    Tuesday, May 5, 2020 6:11 PM

Answers

All replies

  • User197322208 posted
    _dbContext.Patients.Include(p=>Sex).Where(p => p.PatientRowID == gid)
    Tuesday, May 5, 2020 6:37 PM
  • User-79977429 posted

    Thanks for reply

    But as i told in my first post, i don't have Include method in my dbContext!

    Tuesday, May 5, 2020 6:41 PM
  • User475983607 posted

    I assume Sex can only be Male or Female?  if so, Sex should be a lookup table or an enum.

        public class Patient
        {
            public Guid PatientId { get; set; }
            public string PatientCaseId { get; set; }
            public string Firstname { get; set; }
            public string Lastname { get; set; }
            public int? SexId { get; set; }
            public SexLookUp Sex { get; set; }
        }
    
        public partial class SexLookUp
        {
            public int SexId{ get; set; }
            public string Sex { get; set; }
        }
    public class MvcDbDemoContext : DbContext
        {
            public MvcDbDemoContext (DbContextOptions<MvcDbDemoContext> options)
                : base(options)
            {
            }
    
            public DbSet<Patient> Patient { get; set; }
            public DbSet<SexLookUp> Sex { get; set; }
    
            protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                modelBuilder.Entity<Patient>().ToTable("Patients").HasKey(p => p.PatientId);
                modelBuilder.Entity<Patient>().HasOne(s => s.Sex);
                modelBuilder.Entity<Patient>().Property(p => p.Firstname).HasMaxLength(50);
                modelBuilder.Entity<Patient>().Property(p => p.Lastname).HasMaxLength(50);
    
                modelBuilder.Entity<SexLookUp>().ToTable("SexLookup").HasKey(s => s.SexId);
            }
        }

    Reference documentation

    https://www.learnentityframeworkcore.com/configuration/one-to-many-relationship-configuration

    https://codewithshadman.com/entity-framework-enum-code-first/

    Tuesday, May 5, 2020 8:16 PM
  • User-79977429 posted

    Hi mgebhard

    But i've misunderstood your code. I think your sample code does not solve my problem.

    The 'Sex' entity is a table in database which has a relationship with 'Patients' table via 'SexID' column.

    Here is my db context OnModelCreating method :

    protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                modelBuilder.Entity<Patients>(entity =>
                {
                    entity.Property(e => e.PatientRowID).ValueGeneratedNever();
    
                    entity.HasOne(d => d.Sex)
                        .WithMany(p => p.Patients)
                        .HasForeignKey(d => d.SexID)
                        .HasConstraintName("FK_Patients_Sex");
                });         
    
    
                modelBuilder.Entity<Sex>(entity =>
                {              
                    entity.Property(e => e.SexID).ValueGeneratedNever();
                });
    
                OnModelCreatingPartial(modelBuilder);
            }

    Do am i missing some package or references ?

    Thanks in advance

    Tuesday, May 5, 2020 9:36 PM
  • User475983607 posted

    But i've misunderstood your code. I think your sample code does not solve my problem.

    Your code does not work. 

    My code works and Patient has a foreign key constraint with Sex as expected. I don't see any reason to go from Sex to Patient.  And isn't a Patient also a Person? 

    Did you populate the data?  Have you tried executing a query in SSMS or reviewing the data?  

    Tuesday, May 5, 2020 10:05 PM
  • User-79977429 posted

    Thanks for reply

    I've solved my problem.

    To enable Lazy Loading in ef core, we must add this package to the solution :

    Microsoft.EntityFrameworkCore.Proxies

    Then, in ConfigureServices method (in StartUp.cs) we can enable lazy loading proxies as follow :

    services.AddDbContext<Models.MyDbContext>(
                options => options.UseLazyLoadingProxies()
                .UseSqlServer(Configuration.GetConnectionString("MyDbContextConnectionString")));

    Reference : https://docs.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.proxiesextensions.uselazyloadingproxies?view=efcore-3.1

    Best regards.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, May 6, 2020 8:39 AM
  • User197322208 posted

    If you do LazyLoading and not Include , then you should leave the connection open and floating , so in the View that want to access the properties can go to the database.


     

    Wednesday, May 6, 2020 10:57 AM
  • User475983607 posted

    I recommend using Include()

    Wednesday, May 6, 2020 11:17 AM
  • User-79977429 posted

    The Include method can access after adding this package :

    Microsoft.EntityFrameworkCore.Proxies

    Best regards

    Wednesday, May 6, 2020 11:23 AM