none
Null Reference in a 1..N Relationship EF6 MVC5 RRS feed

  • Question

  • I have a 1 to many relationship in EF6, and i want to do "if else" scenario for a model, so if the child exists update it else create it . However i keep getting a null Reference on a foreachloop. Not sure whats wrong with the code, but its driving me nuts after spending a week trying to solve the issue.

    Controller:

     // GET: Clinical/ClinicalAssets/Details/5
            [Authorize(Roles = "Clinical, Admin")]
            public ActionResult Details(int? ClinicalAssetID)
            {
                if (ClinicalAssetID == null)
                {
                    return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
                }
                var ClinicalASSPATINCVM = (from s in db.ClinicalAssets
                                           join cp in db.ClinicalPATs on s.ClinicalAssetID equals cp.ClinicalAssetID into AP
                                           from subASSPAT in AP.DefaultIfEmpty()
                                           join ci in db.ClinicalINSs on s.ClinicalAssetID equals ci.ClinicalAssetID into AI
                                           from subASSINC in AI.DefaultIfEmpty()
                                           join co in db.ClinicalReadings on s.ClinicalAssetID equals co.ClinicalAssetID into AR
                                           let subASSRED = AR.OrderByDescending(subASSRED => subASSRED.MeterReadingDone).FirstOrDefault()
    
                                           select new ClinicalASSPATINCVM
                                           {
                                               ClinicalAssetID = s.ClinicalAssetID,
                                               AssetTypeName = s.AssetTypeName,
                                               ProductName = s.ProductName,
                                               ModelName = s.ModelName,
                                               SupplierName = s.SupplierName,
                                               ManufacturerName = s.ManufacturerName,
                                               SerialNo = s.SerialNo,
                                               PurchaseDate = s.PurchaseDate,
                                               PoNo = s.PoNo,
                                               Costing = s.Costing,
                                               BudgetCodeJoinColumn = s.BudgetCodeJoinColumn,
                                               TeamName = s.TeamName,
                                               StaffName = s.StaffName,
                                               WarrantyEndDate = subASSPAT.WarrantyEndDate,
                                               InspectionDate = subASSPAT.InspectionDate,
                                               InspectionOutcomeResult = subASSPAT.InspectionOutcomeResult,
                                               InspectionDocumnets = subASSPAT.InspectionDocumnets,
                                               LastTypeofInspection = subASSINC.LastTypeofInspection,
                                               NextInspectionDate = subASSINC.NextInspectionDate,
                                               NextInspectionType = subASSINC.NextInspectionType,
                                               MeterReadingDone = subASSRED.MeterReadingDone,
                                               MeterReadingDue = subASSRED.MeterReadingDue,
                                               MeterReading = (int?)subASSRED.MeterReading ?? 0,
                                               MeterUnitsUsed = (int?)subASSRED.MeterUnitsUsed ?? 0,
                                               FilterReplaced = subASSRED.FilterReplaced,
                                               FilterReplacedDate = subASSRED.FilterReplacedDate
    
    
            }).FirstOrDefault(x => x.ClinicalAssetID == ClinicalAssetID);
    
                if (ClinicalASSPATINCVM == null)
                {
                    return HttpNotFound();
                }
    
    
                return View(ClinicalASSPATINCVM);
            }
    
            [HttpPost]
            [ValidateAntiForgeryToken]
            public ActionResult Details(ClinicalAsset ClinicalAsset)
            {
    
    
                // Relationship -> ClinicalAsset One:Many ClinicalPAT
    
                var existingParent = db.ClinicalAssets
                       .Where(p => p.ClinicalAssetID == ClinicalAsset.ClinicalAssetID)
                        .Include(p => p.ClinicalPATs)
                         .SingleOrDefault();
    
                if (existingParent != null)
                {
                    // Update parent
                    db.Entry(existingParent).CurrentValues.SetValues(ClinicalAsset);
    
                    // Delete children
                    foreach (var existingChild in existingParent.ClinicalPATs.ToList())
                    {
                        if (!ClinicalAsset.ClinicalPATs.Any(c => c.ClinicalAssetID == existingChild.ClinicalAssetID))
                            db.ClinicalPATs.Remove(existingChild);
                    }
    
                    // Update and Insert children
                    foreach (var childModel in ClinicalAsset.ClinicalPATs)
                    {
                        var existingChild = existingParent.ClinicalPATs
                            .Where(c => c.ClinicalAssetID == childModel.ClinicalAssetID)
                            .SingleOrDefault();
    
                        if (existingChild != null)
                            // Update child
                            db.Entry(existingChild).CurrentValues.SetValues(childModel);
                        else
                        {
                            // Insert child
                            var newChild = new ClinicalPAT
                            {
                                WarrantyEndDate = childModel.WarrantyEndDate,
                                //...
                            };
                            existingParent.ClinicalPATs.Add(newChild);
                        }
                    }
    
                    db.SaveChanges();
                }
    
                return View();
            }

    Models:

    namespace Assets.Areas.Clinical.Models
    {
        public class ClinicalAsset
        {
    
            [Key]
            public int ClinicalAssetID { get; set; }
            public int AssetTypeID { get; set; }
            public int? ProductID { get; set; }
            public int? ManufacturerID { get; set; }
            public int? ModelID{ get; set; }
            public int? SupplierID { get; set; }
            [StringLength(100, MinimumLength = 2)]
            public string SerialNo { get; set; }
            [DataType(DataType.Date)]
            [DisplayFormat(DataFormatString = "{0:dd/MM/yy}", ApplyFormatInEditMode = true)]
            public DateTime? PurchaseDate { get; set; }
            [StringLength(100, MinimumLength = 2)]
            public string PoNo { get; set; }
            [DisplayFormat(DataFormatString = "{0:c2}", ApplyFormatInEditMode = true)]
            public decimal? Costing { get; set; }
            public int? TeamID { get; set; }
            public int? BudgetCodeID { get; set; }
            public int? StaffID { get; set; }
            public bool? Filter { get; set; }
    
    
    
            public virtual Model ModelName { get; set; }
            public virtual BudgetCode BudgetCodeJoinColumn { get; set; }
            public virtual Product ProductName { get; set; }
            public virtual AssetType AssetTypeName { get; set; }
            public virtual Manufacturer ManufacturerName { get; set; }
            public virtual Staff StaffName { get; set; }
            public virtual Team TeamName { get; set; }
            public virtual Supplier SupplierName { get; set; }
    
            public virtual ICollection<ClinicalPAT> ClinicalPATs { get; set; }
    
    
        }
    }
    
    namespace Assets.Areas.Clinical.Models
    {
        public class ClinicalPAT
        {
           
            [Key]
            //PK
            public int ClinicalPATID { get; set; }
            //Fk
            public int ClinicalAssetID { get; set; }
            public DateTime? WarrantyEndDate { get; set; }
            [DataType(DataType.Date)]
            [DisplayFormat(DataFormatString = "{0:dd/MM/yy}", ApplyFormatInEditMode = true)]
            public DateTime? InspectionDate { get; set; }
            public int? InspectionOutcomeID { get; set; }
            [StringLength(100, MinimumLength = 2)]
            public string InspectionDocumnets { get; set; }
            [DataType(DataType.Date)]
            [DisplayFormat(DataFormatString = "{0:dd/MM/yy}", ApplyFormatInEditMode = true)]
            public DateTime? InspectionDueDate { get; set; }
    
            public virtual InspectionOutcome InspectionOutcomeResult { get; set; }
    
            public ClinicalAsset ClinicalAsset { get; set; }
    
        }
    }

    Context:

     protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
    
                modelBuilder.Entity<ClinicalPAT>()
                .HasRequired<ClinicalAsset>(s => s.ClinicalAsset)
                .WithMany(s => s.ClinicalPATs)
                .HasForeignKey(s => s.ClinicalAssetID);
            }


    Wednesday, July 17, 2019 10:39 AM

All replies

  • What loop are you talking about?

    Also your controller is too fat.

    https://www.c-sharpcorner.com/UploadFile/56fb14/understanding-separation-of-concern-and-Asp-Net-mvc/

    https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions-1/overview/understanding-models-views-and-controllers-cs

    <copied>

    An MVC model contains all of your application logic that is not contained in a view or a controller. The model should contain all of your application business logic, validation logic, and database access logic. For example, if you are using the Microsoft Entity Framework to access your database, then you would create your Entity Framework classes (your .edmx file) in the Models folder.

    A view should contain only logic related to generating the user interface. A controller should only contain the bare minimum of logic required to return the right view or redirect the user to another action (flow control). Everything else should be contained in the model.

    In general, you should strive for fat models and skinny controllers. Your controller methods should contain only a few lines of code. If a controller action gets too fat, then you should consider moving the logic out to a new class in the Models folder.

    <end>

    A thin controller, becuase all the EF code is in a class in the Models folder.

    using Microsoft.AspNetCore.Mvc;
    using PublishingCompany.Models;
    
    namespace PublishingCompany.Controllers
    {
        public class PayRollController : Controller
        {
            private IPayRollDM pdm;
            public PayRollController(IPayRollDM payRollDM)
            {
                pdm = payRollDM;
            }
            public IActionResult Index()
            {
                return View(pdm.GetAll());
            }
    
            public IActionResult Detail(int id = 0)
            {
                return id == 0 ? null : View(pdm.Find(id));
            }
    
            public ActionResult Create()
            {
                return View(pdm.Add());
            }
    
            [HttpPost]
            public ActionResult Create(PayRollVM.Payroll payroll, string submit)
            {
                if (submit == "Cancel") return RedirectToAction("Index");
                
                if (!ModelState.IsValid) return View(pdm.PopulateSelectedList(payroll));
    
                if (pdm.BlnFindPayRollByAuthorId(int.Parse(payroll.AuthorTypeId)))
                {
                    ModelState.AddModelError(string.Empty, "Author has an existing PayRoll record.");
                }
    
                if (!ModelState.IsValid) return View(pdm.PopulateSelectedList(payroll));
    
                pdm.Add(payroll);
                return RedirectToAction("Index");
            }
            public ActionResult Edit(int id = 0)
            {
                return id == 0 ? null : View(pdm.Update(id));
            }
    
            [HttpPost]
            public ActionResult Edit(PayRollVM.Payroll payroll, string submit)
            {
                if (submit == "Cancel") return RedirectToAction("Index");
    
                if (!ModelState.IsValid) return View(payroll);
    
                pdm.Update(payroll);
                return RedirectToAction("Index");
            }
            public IActionResult Delete(int id = 0)
            {
                if (id > 0) pdm.Delete(id);
    
                return RedirectToAction("Index");
            }
    
            public ActionResult Cancel()
            {
                return RedirectToAction("Index", "Home");
            }
        }
    }

    Wednesday, July 17, 2019 5:39 PM