简体   繁体   中英

Insert new Entity with one to many relationship not creating records in both tables

I'm using MVC5 and EF6 Code First to create a new Company entity that can have many Contact entities. However, only the Company record is being written to the database.

Models:

public class Company
{
    public virtual int CompanyId { get; set; }

    [Required]
    public virtual string Name { get; set; }

    [Required]
    public virtual Address Address { get; set; }

    [Required]
    public virtual string Phone { get; set; }

    public virtual string Email { get; set; }

    // can have many Contacts
    public virtual IEnumerable<Contact> Contacts { get; set; }
}

public class Contact
{
    public virtual int ContactId { get; set; }

    [Required]
    public virtual string Title { get; set; }

    [Required]
    public virtual string Forename { get; set; }

    [Required]
    public virtual string Surname { get; set; }

    [Required]
    public virtual string Phone { get; set; }

    public virtual string Email { get; set; }

    // belongs to one Company
    public virtual Company Company { get; set; }
}

Controller:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Create_POST([Bind(Include = "CallerType,Name,Address,Phone,Email,Contacts")] CompanyViewModel viewModel)
    {
        if (ModelState.IsValid)
        {
            // tried commented code to make sure it wasn't a problem with my repository and contact records aren't saved to database...

            //var context = new EfDbContext();

            //var company = new Company
            //{
            //    Name = viewModel.Name,
            //    Phone = viewModel.Phone,
            //    Address = viewModel.Address,
            //    Email = viewModel.Email
            //};

            //context.Companies.Add(company);

            //var contact = new Contact
            //{
            //    Company = company,
            //    Title = "mr",
            //    Forename= "f",
            //    Surname = "s",
            //    Phone = "132"
            //};

            //var contact2 = new Contact
            //{
            //    Company = company,
            //    Title = "mr",
            //    Forename = "for",
            //    Surname = "sur",
            //    Phone = "987"
            //};

            //var contacts = new List<Contact> {contact, contact2};

            //company.Contacts = contacts;

            //context.SaveChanges();


            var contacts = viewModel.Contacts.Select(c => new Contact
            {
                Title = c.Title,
                Forename = c.Forename,
                Surname = c.Surname,
                Phone = c.Phone,
                Email = c.Email
            });

            var company = new Company
            {
                Name = viewModel.Name,
                Phone = viewModel.Phone,
                Address = viewModel.Address,
                Email = viewModel.Email,
                Contacts = contacts
            };

            await _companyRepository.CreateAsync(company);

            var redirectUrl = new UrlHelper(Request.RequestContext).Action("Create", "Enquiry", new { id = company.CompanyId, callerType = viewModel.CallerType });
            return Json(new { Url = redirectUrl });
        }

        Response.StatusCode = 400;

        return PartialView("~/Views/Company/_Create.cshtml", viewModel);
    }

Repository:

    public async Task<TEntity> CreateAsync(TEntity entity)
    {
        if (entity == null) throw new ArgumentNullException(nameof(entity));
        DbContext.Set<TEntity>().Add(entity);
        await DbContext.SaveChangesAsync();
        return entity;
    }

I was under the impression that the DbContext would 'know' that because it's Contacts collection is populated it would create Contact records that link to the created Company . Or do I have to create a Contact instead as this is the table with the foreign key in it and EF will 'know' to create the Company first?

Or is it necessary to actually save the Company entity first using SaveChanges() and then assign it to the Contact records and perform a second SaveChanges() ?
If this is the case then would I need to use Database.BeginTransaction() ?

Any guidance on this would be great as this is my first time using Entity Framework.

Contacts must be an ICollection . EF doesn't support IEnumerable as navigation properties, because it's impossible to add items to them.

This also means that you should change the code that creates contacts :

var contacts = viewModel.Contacts.Select(c => new Contact
{
    Title = c.Title,
    Forename = c.Forename,
    Surname = c.Surname,
    Phone = c.Phone,
    Email = c.Email
}).ToList();  // <= ToList() added

Your relationships should be set up within your DbContext by overriding the OnModelCreating method

I'm new to Entity Framework myself, but found that the methods names aid in learning how to set up relationships

Hopefully the below can help

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Company>()
                    .HasMany(c => c.Contacts)
                    .WithRequired(co => co.Company)
                    .HasForeignKey(co => co.CompanyId);
}

You can also set up cascading within your relationship, so that when one entity is removed, the related entities are also deleted, which may be something to consider if you ever need to delete a Company

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM