C# 使用EF插入具有多对多关系的操作

C# 使用EF插入具有多对多关系的操作,c#,asp.net-mvc,entity-framework,many-to-many,C#,Asp.net Mvc,Entity Framework,Many To Many,我有两个模型课: 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 ICol

我有两个模型课:

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; }
}
公开课候选人
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共ICollection作业{get;set;}
}
公开课工作
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共ICollection候选者{get;set;}
}
我的DbContext名称是JobsContext

上述代码生成me 3个表候选、作业和候选作业(由EF自动生成)

现在我在Jobs表中有了记录:Id=1,Name=“Sales”:Id=2,Name=“Engineer”

我想将一个新的候选人和Jobs表中的两条记录关联起来,我将把它插入候选人表中

在插入候选人之前,我知道Jobs表的Id&我不想调用数据库来从Jobs表获取更多细节


如何使用Entity Framework 5实现这一点?

有两个选项

如果要放置相同的上下文和候选对象,只需将现有候选对象添加到作业中即可。 例如: 创建候选人并将其保存到数据库:

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();
然后,创建您的作业:

var job = new Job() { Name = "Good Job" }; //id 1
最后,将您的候选人添加到新的
job
变量中,将该job添加到上下文中并保存更改

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


如果使用的上下文与创建候选对象时使用的上下文不同,则可以创建新的候选对象,并在将其添加到作业之前将其附加到上下文

//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);
通过仅设置ID来创建候选对象

var existingCandidate3 = new Candidate() { Id = 3 };
将对象附加到新上下文。注意:如果上面示例中的上下文仍然存在,它将不允许您这样做,因为它已经在跟踪候选人

将状态设置为“未更改”,因为我们不想创建新的候选对象,只需使用现有的候选对象即可

newContext.Entry(existingCandidate3).State = System.Data.EntityState.Unchanged;
添加它并保存更改

job.Candidates.Add(candidate1);
job.Candidates.Add(candidate2);
context.Jobs.Add(job);
context.SaveChanges();
existingJob.Candidates.Add(existingCandidate3);
newContext.SaveChanges();
完成了

这个怎么样

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();

一个非常简单的解决方案是创建与表完全相同的外部参照表视图(视图\表格名称\原始)。然后在EF中将该视图更新为不带外键的实体。从他们的使用上下文。查看\u tablename\u raw.Add(…),它将无缝工作。

在第一个选项中,您将进行2次数据库调用1)以插入候选人2)将候选人与作业关联。我想在一个INSERT本身上完成它,比如JobsContext.candidates.Add(candidate),它包含一个现有的作业。请参阅:在第一个示例中,您可以在创建候选对象后删除
SaveChanges
调用,并在创建候选对象和作业后调用一次
SaveChanges
。但是,EF仍然会将其转换为几个不同的数据库调用(每个表至少一个)。您的问题听起来像是希望在将候选人添加到工作之前避免对候选人表进行
SELECT
。我修改了代码以更正状态更改,您的代码中缺少了“实体”:正确的是System.Data.Entity.EntityState.Unchanged“如果您使用的上下文与您创建的上下文不同,那么候选者会使用”您的意思是相同上下文的不同对象(
var a=new context1();var b=new context1();
)或不同上下文(
var a=new context1();var b=new context2();
)?@cbeckner如果您调用
context.Jobs.Attach(new Job>),情况如何{Id=salesJobId});
first?感谢您的回答。我尝试了您在上面输入的第二个代码。EF在包含空值的Jobs表中创建了一个Id为3和4的新条目,并将这些Id与该特定候选项相关联。因此它不起作用。@JonahPereira我刚刚用
Attach()更新了我的答案
calls,你也试过了吗?是的,成功了!!&正是我想要的。谢谢@HenkMollema@JoSmo只要这两个实体都连接到当前数据库上下文,就会得到相同的结果。