问题
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);
}
}
回答1:
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);
回答2:
I'm assuming your have auto generated id for parent entity, in that case you need to add parent entity to DbSet and save changes in order to EF Core sets the generated value for property.
Try this code and you'll save the information:
// Create instance for parent class
var p = new Parent { Name = "some name", FY = SelectedYear, ... };
// Add entity instance to db context
_context.Parent.Add(p);
// Save changes, this action sets the generated id value to entity's property
_context.SaveChanges();
// Create instances for child entities
var c1 = new Child { ItemName = "Abc", ParentID = p.ParentID };
var c2 = new Child { ItemName = "Rst", ParentID = p.ParentID };
// Add child to db context
_context.Child.Add(c1);
_context.Child.Add(c2);
// Save changes
_context.SaveChanges();
It seems like saving fails because each child instance doesn't have value for ParentID property and that column doesn't allow null values.
Let me know if this is useful
来源:https://stackoverflow.com/questions/46517584/how-to-add-a-parent-record-with-its-children-records-in-ef-core