Example 1 below used to work but it is not working in EF Core. Question: How to make example 2 below work?
Example 1:
child c1 = new child();
child c2 = new child();
parent p=new parent();
p.child.Add(c1);
p.child.Add(c2);
using (var db = new DbContext())
{
db.parent.Add(p);
db.SaveChanges();
}
Entity Parent P has children C1, and C2 in a one-to-one relationship. Trying to insert a parent and its children records. But in the following code VS2017
's editor's intellisense
does not recognize .child
at the line cust.child.Add(c1);
. Maybe, EF Core has something better for inserting parent/child records. I'm using ASP.NET MVC Core 1.1.1
and EF Core 1.1.1.
Example 2:
...
Parent p = new Parent { Name = "some name" , FY = SelectedYear, ... };
Child c1 = new Child { ItemName = "Abc"};
Child c2 = new Child { ItemName = "Rst"};
p.child.Add(c1);
p..child.Add(c2);
_context.Add(p);
_context.SaveChanges();
UPDATE:
Per a request from @GlennSills
, following is an example of well known Blogging Db (taken from this ASP.NET tutorial):
public class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{ }
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
In the Create(...)
method below, at line blog.Posts.Add(c);
I get the error: Object reference not set to an instance of an object.
public class BlogsController : Controller
{
private readonly BloggingContext _context;
public BlogsController(BloggingContext context)
{
_context = context;
}
....
....
// POST: Blogs/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("BlogId,Url")] Blog blog)
{
if (ModelState.IsValid)
{
Post c = new Post();
blog.Posts.Add(c);
_context.Add(blog);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(blog);
}
}
Entity Framework Core allows you to use the navigation properties in your model to load related entities. There are three common O/RM patterns used to load related data. Eager loading means that the related data is loaded from the database as part of the initial query.
By default, EF maps the inheritance using the table-per-hierarchy (TPH) pattern. TPH uses a single table to store the data for all types in the hierarchy, and a discriminator column is used to identify which type each row represents.
Use the DbSet. Add method to add a new entity to a context (instance of DbContext ), which will insert a new record in the database when you call the SaveChanges() method.
Saving child objects along with their parent definitely works. The key is you need to model your entities in such a way that EF knows about all the relationships. Here is a really simple application doing it that you can take a look at. Simple app on github
I have a parent that looks like
using System.Collections.Generic;
namespace EFParentChild
{
public class Parent
{
public int ParentId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public List<Child> Children { get; set; } = new List<Child>();
}
}
here's the child
namespace EFParentChild
{
public class Child
{
public int Id { get; set; }
public int ParentId { get; set; }
public Parent Parent { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
Here is the context:
using Microsoft.EntityFrameworkCore;
namespace EFParentChild
{
class DbParentChild : DbContext
{
public DbSet<Parent> Parents { get; set; }
public DbSet<Child> Children { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=ParentChildDb;Trusted_Connection=True;");
}
}
}
Here is the program that saves the data
static void Main(string[] args)
{
using (var dbContext = new DbParentChild())
{
var parent = new Parent
{
FirstName = "Joe",
LastName = "Smith"
};
parent.Children.Add(
new Child
{
FirstName = "LittleJoe",
LastName = "Smith"
});
parent.Children.Add(
new Child
{
FirstName = "Anne",
LastName = "Smith"
});
dbContext.Add(parent);
dbContext.SaveChanges();
}
}
The key here is that I'm using conventions to tell EF that there is a parent-child relations. Notice how the id names used between the two entities match up. The child has a ParentId that matches ParentId in its parent. Also noticed the foreign key constraint in the child.
I created the tables using the entity framework tooling. You can take that approach yourself or create them by hand if you want. The parent DDL is :
CREATE TABLE [dbo].[Parents] (
[ParentId] INT IDENTITY (1, 1) NOT NULL,
[FirstName] NVARCHAR (MAX) NULL,
[LastName] NVARCHAR (MAX) NULL,
CONSTRAINT [PK_Parents] PRIMARY KEY CLUSTERED ([ParentId] ASC)
);
The child DDL is:
CREATE TABLE [dbo].[Children] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[FirstName] NVARCHAR (MAX) NULL,
[LastName] NVARCHAR (MAX) NULL,
[ParentId] INT NOT NULL,
CONSTRAINT [PK_Children] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_Children_Parents_ParentId] FOREIGN KEY ([ParentId])
REFERENCES [dbo].[Parents] ([ParentId]) ON DELETE CASCADE
);
GO
CREATE NONCLUSTERED INDEX [IX_Children_ParentId]
ON [dbo].[Children]([ParentId] ASC);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With