使用Entity Framework Code First以多对多的关系附加到现有对象

时间:2015-01-15 02:53:34

标签: entity-framework ef-code-first many-to-many asp.net-web-api2

我正在使用Web API2和EF6代码开始使用Rest API,首先从http://www.asp.net/web-api/overview/data/using-web-api-with-entity-framework/part-4上的指南开始 我基本上做同样的事情有多对多的关系,当我创建一个对象时,我们称之为A,我在帖子中包含一个B对象数组作为Bs变量。它们都是在初始帖子中按预期创建的,但是当我添加第二个对象A时,它应该链接到与第一个对象A相同的一个或多个B,而不是匹配现有的B尝试创建新的B,但是B的名称有一个限制,这不会起作用。我如何确保它不会尝试每次创建一个新对象B,而是链接到现有的对象B(如果有的话)?

以下是更详细的示例。

我有两个模型,我们称它们为A和B.它们有多对多的关系

public class A
{
    public int Id { get; set; }
    [Required, StringLength(100), Index("IDX_Name", 2, IsUnique = true)]
    public string Name { get; set; }
    [StringLength(300)]
    public string Description { get; set; }

    public ICollection<B> Bs{ get; set; }
}

模型B

public class B
{
    public int Id { get; set; }
    [Required, StringLength(100), Index("IDX_Name", 2, IsUnique = true)]
    public string Name { get; set; }

    public ICollection<B> As{ get; set; }
}

我不包括自动生成的上下文。 并且在自动生成的Controller脚手架中,对于模型A的Web API POST方法,它看起来像这样

    [ResponseType(typeof(A))]
    public async Task<IHttpActionResult> PostGame(A a)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        db.As.Add(a);
        await db.SaveChangesAsync();

        return CreatedAtRoute("DefaultApi", new { id = a.Id }, a);

    }

所有表格都创建得很好,如果我在第一篇文章中使用以下json创建我的第一个对象:

    {
    "Name": "FirstA",
    "Description": "FirstADesc",
    "Bs" : [{"Name":"FirstB"}]
    }

它可以工作,并且创建了FirstA和FirstB。 如果我然后发布一个也与FirstB obect链接的SecondA

    {
    "Name": "SecondA",
    "Description": "SecondADesc",
    "Bs" : [{"Name":"SecondB"},{"Name":"FirstB"}]
    }

它将取代找到FirstB尝试再次创建它。这是由于约束。

我的第一个猜测是我应该在第二篇文章中使用ID:s。像:

    {
    "Name": "SecondA",
    "Description": "SecondADesc",
    "Bs" : [{"Id":"1"},{"Name":"FirstB"}]
    }

但这也不起作用。

实现此目的的唯一方法是从控制器替换脚手架代码并手动检查Bs中的每个对象(如果已存在)?

基本上它是“标记到帖子问题”...... 我已经查看了Attached vs Detached Data主题并阅读了有关此事的文章,但没有找到答案,我可以理解这是否可以通过一些正确的注释自动完成,或者是否必须在控制器中“手动”完成。

提前致谢!

1 个答案:

答案 0 :(得分:0)

对此没有太多回应, 结束循环并手动检查现有条目,如下所示。

[ResponseType(typeof(A))]
public async Task<IHttpActionResult> PostGame(A a)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }
    foreach (var asd in a.Bs.ToList())
    {
    var t = db.Bs.FirstOrDefault(a => a.Name == asd.Name);
      if (t != null)
      {
        a.Bs.Remove(asd);
        a.Bs.Add(t);
      }
    }
    db.As.Add(a);
    await db.SaveChangesAsync();

    return CreatedAtRoute("DefaultApi", new { id = a.Id }, a);

}

不能让人觉得必须有更好的方法。