Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Insert operation with many-to-many relationship using EF

I've two model classes:

public class Candidate
{
  public int Id { get; set; }
  public string Name { get; set; }
  public ICollection<Job> Jobs { get; set; }
}

public class Job
{
  public int Id { get; set; }
  public string Name { get; set; }
  public ICollection<Candidate> Candidates { get; set; }
}

My DbContext name is JobsContext.

The above code generates me 3 tables Candidates, Jobs & CandidatesJobs(autogenerated by EF)

Now I've records in Jobs table : Id = 1, Name = "Sales" : Id = 2, Name = "Engineer".

I want to associate a new Candidate which I'll be inserting into Candidates table with the 2 records from Jobs table.

Before inserting the Candidate I know the Id's of the Jobs table & I don't wish to make a call to the database to get more details from Jobs table.

How do I do this using Entity Framework 5?

like image 669
hendrixchord Avatar asked Oct 02 '13 06:10

hendrixchord


People also ask

How do I create a many-to-many relationship in Entity Framework?

A many-to-many relationship is defined in code by the inclusion of collection properties in each of the entities - The Categories property in the Book class, and the Books property in the Category class: public class Book. { public int BookId { get; set; }

How do you do a many-to-many relationship?

A many-to-many relationship occurs when multiple records in a table are associated with multiple records in another table. For example, a many-to-many relationship exists between customers and products: customers can purchase various products, and products can be purchased by many customers.

What is another way to configure a many-to-many relationship in OnModelCreating method?

Step 1 – Add foreign key property to other entities, in the joining entity. Step 2 – Add collection navigation property on the other entities towards the joining entity. Step 3 – Next create DB Context OnModelCreating() method configure both the foreign keys in the joining entity as a composite key using Fluent API.

How you can load related entities in EF?

Entity Framework supports three ways to load related data - eager loading, lazy loading and explicit loading. The techniques shown in this topic apply equally to models created with Code First and the EF Designer.


2 Answers

How about this?

Job salesJob; // already fetched from db
Job engineerJob; // already fetched from db

Candidate candidate = new Candidate();
candidate.Name = "John Doe";
candidate.Jobs = new List<Job>(); // you could also do this in the constructor of Candidate
candidate.Jobs.Add(salesJob);
candidate.Jobs.Add(engineerJob);

context.SaveChanges();

This only works if you already fetched the jobs from the database within the same instance of the DbContext, else EF will think that the jobs are 'new' and tries to insert them. If you only have the ids, you could try the following:

var salesJob = new Job { Id = salesJobId };
var engineerJob = new Job { Id = engineerJobId };

context.Jobs.Attach(salesJob);
context.Jobs.Attach(engineerJob);

candiate.Jobs.Add(salesJob);
candiate.Jobs.Add(engineerJob);
context.SaveChanges();
like image 108
Henk Mollema Avatar answered Sep 20 '22 05:09

Henk Mollema


There are two options.

If you are going to have the same context and candidate objects laying around, you can simply add the existing candidate objects to the job. For example: Create your candidates and save them to the database:

JobsContext context = new JobsContext();
var candidate1 = new Candidate() { Name = "John Smith" }; //id 1
var candidate2 = new Candidate() { Name = "Jane Smith" }; //id 2
var candidate3 = new Candidate() { Name = "John Doe" }; //id 3
context.Candidates.Add(candidate1);
context.Candidates.Add(candidate2);
context.Candidates.Add(candidate3);
context.SaveChanges();

Then, create your job:

var job = new Job() { Name = "Good Job" }; //id 1

Finally, add your candidates to the new job variable, add the job to the context and save changes.

job.Candidates.Add(candidate1);
job.Candidates.Add(candidate2);
context.Jobs.Add(job);
context.SaveChanges();

OR

If you are using a DIFFERENT context from the one you created the candidates with, then you can create a new candidate object and attach it to the context prior to adding it to the job.

//different context from above example
JobsContext newContext = new JobsContext();
//this can be a new or existing job, using the job from the example above here
var existingJob = newContext.Jobs.FirstOrDefault(j => j.Id == 1);

Create our candidate object by setting only the ID

var existingCandidate3 = new Candidate() { Id = 3 };

Attach the object to the new context. Note: if the context from the example above is still around, it will not let you do this since it is already tracking the candidate.

newContext.Candidates.Attach(existingCandidate3);

Set the state to Unchanged since we don't want to create a new candidate, just use the existing one.

newContext.Entry(existingCandidate3).State = System.Data.EntityState.Unchanged;

Add it and save the changes.

existingJob.Candidates.Add(existingCandidate3);
newContext.SaveChanges();

Done!

like image 34
cbeckner Avatar answered Sep 20 '22 05:09

cbeckner