Answered by:
Writing Parent and Child data at the same time.

Question
-
User-1691787363 posted
Morning,
Hope someone can help with with this. I have two models:
public class Parent { public int ParentID { get; set; } public string Data { get; set; } public virtual ICollection<Child> Children { get; set; } } public class Child { public int ChildID { get; set; } public int ParentID { get; set; } public string Data { get; set; } public virtual Parent Parent { get; set; } }
What I would like to be able to do or know how to do is insert records into both in one hit. Something like the below:
public async Task<IActionResult> CreateParent(Parent parent) { parent.Child.Add(new Child { Data = "SomeData" }); _context.Add(parent); await _context.SaveChangesAsync(); }
Obviously before the parent record is saved, I don't have the PK from the Parent table to put in the FK of the Child table and I believe that is why I am getting Object 'reference not set to an instance of an object.', but obviously I could be completely wrong.
I thought, wrong or right, it would potentially automagically add the FK as the insert would be as it would be a single Company object with a child contained.
Hope that makes sense and someone can help me out with this, cheers
Saturday, February 20, 2021 11:50 AM
Answers
-
User1120430333 posted
You are getting the exception message because parent is null valued object, the child is a null valued object or a property in either object is a null value property. If it's null, then it doesn't exist in memory. When code references/access an object or object's property is null, you are going to get the exception you are getting. You can use the debugger Quickwarch on a breakpoint and examine the content of the object.
EF will automatically populate the parent ID to all child objects I n the collection. Maybe you need to instance the child collection in the parent before you add a child to the collection.
Also how is a parent going to be an object in the child? It makes no sense and could be a possible circular reference.
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Saturday, February 20, 2021 1:22 PM
All replies
-
User1120430333 posted
You are getting the exception message because parent is null valued object, the child is a null valued object or a property in either object is a null value property. If it's null, then it doesn't exist in memory. When code references/access an object or object's property is null, you are going to get the exception you are getting. You can use the debugger Quickwarch on a breakpoint and examine the content of the object.
EF will automatically populate the parent ID to all child objects I n the collection. Maybe you need to instance the child collection in the parent before you add a child to the collection.
Also how is a parent going to be an object in the child? It makes no sense and could be a possible circular reference.
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Saturday, February 20, 2021 1:22 PM -
User-1691787363 posted
That's a bit of a mouthful :)
I modified this line:public virtual ICollection<Child> Children { get; set; }
To this:
public virtual ICollection<Child> Children { get; set; } = new Collection<Child>();
Cheers,
Saturday, February 20, 2021 1:32 PM -
User475983607 posted
LCHolmes
Obviously before the parent record is saved, I don't have the PK from the Parent table to put in the FK of the Child table and I believe that is why I am getting Object 'reference not set to an instance of an object.', but obviously I could be completely wrong.You did not provide enough code to figure out how your design works. You also did not provide the exception message so we have no idea what is null. The error message always shows the line of code that caused the null exception.
If your table design uses an Identity column to populate the parent Id then you can save the parent record first so the Identity column can create the ID. The ID is passed back to the entity. Then you can save the child record(s).
There can also be an issue with the View design that causes a the model binder to create a null Parent. This is a very common coding error where the HTML form names do not match the action's input parameter property names.
Saturday, February 20, 2021 1:37 PM -
User-1691787363 posted
I followed the "Fully Defined relationships" part of of this:
Relationships - EF Core | Microsoft Docs
So the list of children in your parent:
public virtual ICollection<Child> Children { get; set; }
and a single link back to the parent in the child:
public virtual Parent Parent { get; set; }
Could you please explain what I am doing wrong just off this statement as I'm am not understanding you mean against what I am reading:
Also how is a parent going to be an object in the child? It makes no sense and could be a possible circular reference.
Cheers
Saturday, February 20, 2021 1:51 PM -
User475983607 posted
and a single link back to the parent in the child:You are correct. The Parent property in the Child allows for accessing the Parent from the Child.
Also how is a parent going to be an object in the child? It makes no sense and could be a possible circular reference.Your Entity Model design is correct. But, you can run into trouble if you use Entities in your UI (MVC). Entities are objects that represent database tables and let you interact with table though C# code. CRUD operation should be handled in Entity framework while UI should be handled in MVC View Models. A typical MVC design contains models populated from Entities types. These MVC View Models are used to populate the Views and send data from an HTML form to an action.
Many MVC examples use Entities in MVC views but this only works for very simple applications.
Saturday, February 20, 2021 2:46 PM -
User-1691787363 posted
Ah,
Obviously this goes back to the lack of info on my project. I have a Models > Repository > ViewModel > UI in my project, as you can image there is quiet a lot of bits, its one of the reasons I tried to massively simplify the actual question. As all my action results look more like this:
[HttpPost] [ValidateAntiForgeryToken] [Authorize(Roles = "Administrator, Create")] public async Task<IActionResult> CreateSchedule(int id, CompanySchedule companySchedule) { if (ModelState.IsValid && companySchedule.CompanyID == id) { await _unitOfWork.CompanyScheduleRepository.AddAsync(companySchedule); await _unitOfWork.Complete(); return RedirectToAction(nameof(Details), new { id = companySchedule.CompanyID }); } return View("CreateEditSchedule", (ScheduleViewModel) companySchedule); }
Calling from my repository like this:
public void EditCompany(Company company, int userID) { company.CompanyChangeLogs = new Collection<CompanyChangeLog> { new CompanyChangeLog() { ChangeType = "Edit", UserID = userID, CompanyChangeLogDetails = new Collection<CompanyChangeLogDetail>( ObjectHelper.Compare(company, _dbSet.AsNoTracking().Where(c => c.CompanyID == company.CompanyID).First()) .Select(c => new CompanyChangeLogDetail { PropertyName = c.PropertyName, OldValue = Convert.ToString(c.valA), NewValue = Convert.ToString(c.valB) }) .ToList()) } }; _dbSet.Update(company); }
Then you have the models, the the view models, then there operators etc... on top of that, I didn't think putting all that in for something I knew was a basic question and not being able to spot what it was, so I thought I would get a quicker answer from a simplified question
Basically I hadn't created an Instance of the collection, because D'Oh. Thanks for your help and explanation of what was meant. I'll put more detail next time
Edit: my UI sends ViewModels back to my POST actions, however I have implicit operators in place so I can just recieve them as a instance of the Model with no extra conversions or mappings in my actions, i see how with out that info it would look like my UI was sending Entities and would cause confusion :)
Saturday, February 20, 2021 5:22 PM -
User1120430333 posted
I see in the example that what you are doing is correct. I never make the model classes and let EF make them, becuase I set up the database with tables using a DBA tool like SSMS. I then point EF using database first approach or use the EF Core UI tool to generate the model classes. I never even look at them.
It just seemed strange that the parent object is in the child. I mean really if you were doing it manually by using something like the DAO pattern, One would use the DAOParent to save the parent, the ID of inserted parent is returned to the parent object by EF with parent in memory. One takes the ID from parent and call DAOChild passing in the ID of the parent ID to populate the foreign-key property of the child.
Data Access Object (DAO) design pattern in Java - Tutorial Example (javarevisited.blogspot.com)
The DTOParent with DTOChildren witthin parent would be sent to the data access layer. That's how I like to do it
You should looking into using the DAO or the generic repository pattern.
Data Access Object (DAO) design pattern in Java - Tutorial Example (javarevisited.blogspot.com)
Data Transfer Object Design Pattern in C# - CodeProject
Some still like to use the pattern regardless, but I avoid it, becuase it's not flexible and EF already uses the pattern
Generic Repository Pattern implemented in .NET Core with EF Core | by Marek Żyła | Medium
4 Common Mistakes with the Repository Pattern - Programming with Mosh
Is the repository pattern useful with Entity Framework Core? – The Reformed Programmer
It's just some FYI. :)
Try to implement some SoC if you can.
Separation of concerns - Wikipedia
Understanding Separation Of Concern in ASP.NET MVC (c-sharpcorner.com)
Layered or Ntier.....
Chapter 3: Architectural Patterns and Styles | Microsoft Docs
Saturday, February 20, 2021 7:14 PM -
User-1691787363 posted
Thank you.
So let me explain my project a little more, away from the primary question as you are giving useful feedback, and its always good to take advantage while that is on offer :)
So my Solution structure is:
DAL - Containing my dbcontext/dbset/onmodelcreating - this is also doing my seed setting schema etc...
Data - Containing all of my Entity Models
Migrations - Just holds my migration data as it is just a mess elsewhere
Repository - holds all of my "queries" etc... all based around a base class and a UnitOfWork
Library - holds all of my common classes (including view models)
API - which provides a raw data connection via the repository
MVC - provides a UI, and the controllers use the repository
This should allow me to add any kind of UI project to my solution and just call the same things from my repository to return the same data no matter the UI, so the whole project is seperated. Thoughts?
So from any frontend project i can call from my repository project, my repository project calls from my DAL, my models are seperated from my vm's and my ui can only call from my vm's so I have an abstraction layer in place
So I can do things like this:
public void EditCompany(Company company, int userID) { company.CompanyChangeLogs = new Collection<CompanyChangeLog> { new CompanyChangeLog() { ChangeType = "Edit", UserID = userID, CompanyChangeLogDetails = new Collection<CompanyChangeLogDetail>( ObjectHelper.Compare(_dbSet.AsNoTracking().Where(c => c.CompanyID == company.CompanyID).First(), company) .Select<ObjectCompare, CompanyChangeLogDetail>(x => x) .ToList()) } }; _dbSet.Update(company); }
but i can also do things like:
.Select<CompanyChangeLogDetail, CompanyChangeLogDetailViewModel>(x => x)
or I can just take either and convert them like (CompanyChangeLogDetailViewModel) CompanyChangeLogDetail or recieve a CompanyChangeLogDetailViewModel to a POST action like public async Task<CompanyChangeLogDetail companyChangeLogDetail )Saturday, February 20, 2021 8:02 PM -
User1120430333 posted
Well one issue I see off the bat in the 'new' is glue not being applied. .
New is Glue | Blog (ardalis.com)
The view models IMHO should be in the Models folder. in the MVC project.
ASP.NET - Writing Clean Code in ASP.NET Core with Dependency Injection | Microsoft Docs
You're are using Core so there is no reason that DI cannot be used throughout your solution, including DI of DbContext into a class. The clean code can be applied if you are not using Core as well.
Understanding Models, Views, and Controllers (C#) | Microsoft Docs
<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.
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>
domain model object = DM and viewmodel object - VM in the Models folder.
The major difference in the example code on Github you can examine is WebAPI using DAL with DAO pattern using EF and the DTO pattern.
darnold924/PublishingCompany (github.com)
Also global exception handling is being used in the MVC and WebAPI projects and there is no try/catch used in client side of service side projects.
How to Catch All Exceptions in C# & Find All Application Errors – Stackify
HTH
Maybe the common classes should be in the Models folder.
Sunday, February 21, 2021 12:33 AM