如何在不重复的情况下添加与现有实体有关系的新实体?(EF 6.1)

Lor*_*son 5 c# entity-framework code-first asp.net-web-api

首先使用 Web API 2 和 EF 6.1 代码。

我正在尝试添加一个Template与现有TimePeriodsStations.

public class Template
{
    public int TemplateID { get; set; }
    public string Name { get; set; }

    public List<TimePeriod> TimePeriods { get; set; }
    public List<Station> Stations { get; set; }
}

public class Station
{
    public int StationID { get; set; }
    public string Name { get; set; }

    public List<Template> Templates { get; set; }
}

public class TimePeriod
{
    public int TimePeriodID { get; set; }
    public TimeSpan From { get; set; }
    public TimeSpan To { get; set; }
    public List<Template> Templates { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

新模板对象包含一个列表Station和一个TimePeriod具有正确 ID/主键的列表。我希望 EF 能够通过查看它们的主键来识别相关实体已经存在,但似乎没有。相反,所有相关实体都会再次添加,从而导致重复。

private SchedulingContext db = new SchedulingContext();

[ResponseType(typeof(Template))]
public IHttpActionResult PostTemplate(Template template)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    db.Templates.Add(template);
    db.SaveChanges();

    return CreatedAtRoute("DefaultApi", new { id = template.TemplateID }, template);
}
Run Code Online (Sandbox Code Playgroud)

这与我使用新上下文有关吗?如果是这样,我该如何防止这种行为?

感谢 Evandro 的解决方案:

public void PostTemplate(Template template)
{
    db.Templates.Add(template);

    foreach (var item in template.Stations)
    {
        db.Entry<Station>(item).State = EntityState.Unchanged;
    }

    foreach (var item in template.TimePeriods)
    {
        db.Entry<TimePeriod>(item).State = EntityState.Unchanged;
    }
    db.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)

Eva*_*tti 2

洛伦兹,这是实体框架的默认行为。您必须根据系统应该做什么来明确定义您的自定义行为。

首先,您可以使用以下示例访问上下文中实体的状态:

   EntityState state = db.Entry<Station>(station).State;
Run Code Online (Sandbox Code Playgroud)

您可以打印状态,然后查看 EF 正在做什么。

现在,当您第一次收到 Template 的实例时,它在上下文中的状态将为Detached

将其添加到上下文后,状态将更改为“已添加”。这将适用于模板、站和时间段。

即使您正确设置了 Id(主键),EF 也会丢弃 ids,创建新的 Id 并向表中添加新行,这就是您的程序所发生的情况。这就是我设法在我的代码中重现的内容。

您必须为每个实体定义 EntityState ,以便 EF 知道它不应该保留新项目。以下是 EF 6.1 中的可能值:

// This is probably what you are looking for
db.Entry<Station>(station).State = EntityState.Unchanged;

// This one maybe, if you are receiving updated values for the State
db.Entry<Station>(station).State = EntityState.Modified; 

// Others that may apply for other scenarios
db.Entry<Station>(station).State = EntityState.Detached;
db.Entry<Station>(station).State = EntityState.Added;
db.Entry<Station>(station).State = EntityState.Deleted;
Run Code Online (Sandbox Code Playgroud)

由于模板对于 Station 和 TimePeriod 有多个 iten,因此您必须迭代它们并将每一个设置为我假设的“未更改”或“已修改”。

让我知道它是否有效。