2017-08-10 9 views
0

を挿入します。エンティティAssignmentAssignmentTypeの外部キーを割り当てて、ナビゲーションプロパティAssignmentTypeをヌルに設定すると、同じエラーが発生します(Comments foreachループではなく、Assignmentsのforeachループ内にあります)。Entity Frameworkのは、私はEntity Frameworkの6を使用していると私は、次のエラーを取得しておく既存のナビゲーションプロパティエンティティ

エンティティフレームワークはエンティティAssignmentTypeを追跡していますが、それはなぜそれが新しいエンティティであり、既存のエンティティではないと考えているのですか?

エンティティReportingAssignmentの間に多対1の関係があります。

[Route("")] 
    [HttpPost] 
    public IHttpActionResult Add(ReportingDTO data) 
    {    
     Reporting reporting = new Reporting { ID = Guid.NewGuid(), Date = DateTime.Now };      

     foreach (Assignment assignment in data.Assignments) 
     { 
      _db.Entry(assignment.AssignmentType).State = EntityState.Unchanged; 

      if (assignment.Reporting.Count > 0) 
      { 
       _db.Entry(assignment).State = EntityState.Added; 
       _db.Entry(assignment).State = EntityState.Modified; 
      } 

      reporting.Assignment.Add(assignment); 
     } 

     foreach (Comment comment in data.Comments) 
     { 
      comment.ID = Guid.NewGuid(); 
      comment.AssignmentID = comment.Assignment.ID; 
      comment.Assignment = null; 
      comment.ReportingID= reporting.ID; 
     } 

     using(var transaction = _db.Database.BeginTransaction()) 
     { 
      _db.Reporting.Add(reporting); 
      _db.Comments.AddRange(data.Comments); 
      _db.SaveChanges(); 

      transaction.Commit(); 
     } 

     return Ok(reporting); 
    } 

Reporting.cs

[Table("Reporting")] 
public partial class Reporting 
{ 
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] 
    public Reporting() 
    { 
     Assignment= new HashSet<Assignment>(); 
    } 

    [Key] 
    public Guid ID{ get; set; } 

    [Column(TypeName = "date")] 
    public DateTime Date{ get; set; } 

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] 
    public virtual ICollection<Assignment> Assignment{ get; set; } 
} 

Assignment.cs

[Table("Assignment")] 
public partial class Assignment 
{ 
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] 
    public Assignment() 
    { 
     Reporting = new HashSet<Reporting>(); 
    } 

    [Key] 
    public Guid OID { get; set; } 

    [Required] 
    [StringLength(100)] 
    public string Name { get; set; } 

    public Guid AssignmentTypeID { get; set; } 

    [Required] 
    [StringLength(100)] 
    public string Project { get; set; } 

    public bool Completed { get; set; } 

    [ForeignKey("AssignmentTypeID")] 
    public virtual AssignmentType AssignmentType { get; set; } 

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] 
    public virtual ICollection<Reporting> Reporting { get; set; } 
} 

AssignmentType

[Table("AssignmentType")] 
public partial class AssignmentType 
{ 
    [Key] 
    public Guid ID { get; set; } 

    [Required] 
    [StringLength(100)] 
    public string Name { get; set; }   
} 
+0

あなたは次のような外部キーを持っていますか?Assignment.AssignmentTypeId? – Atlasmaybe

+0

はい、あります。 ReportingDTOでは、このフィールドはnullに等しい。 – adiii4

+0

データモデルを投稿できますか? – Atlasmaybe

答えて

1

このような何かを試してみてください:

public IHttpActionResult Add(ReportingDTO data) 
{    
    Reporting reporting = new Reporting { ID = Guid.NewGuid(), Date = DateTime.Now };      

    foreach (Assignment assignment in data.Assignments) 
    { 
     if (assignment.ID != null) 
     { 
      _db.Assignments.Attach(assignment); 
      _db.Entry(assignment).State = EntityState.Modified; 
     } 
     else 
     { 
      assignment.ID = Guid.NewGuid(); 
     } 

     if (assignment.AssignmentType != null) 
     { 
      assignment.AssignmentTypeID = assignment.AssignmentType.ID; 
      assignment.AssignmentType = null; 
     } 
    } 

    reporting.Assignment.AddRange(data.Assignments); 

    foreach (Comment comment in data.Comments) 
    { 
     comment.ID = Guid.NewGuid(); 
     comment.AssignmentID = comment.Assignment.ID; 
     comment.Assignment = null; 
     comment.ReportingID = reporting.ID; 
    } 

    _db.Reporting.Add(reporting); 
    _db.Comments.AddRange(data.Comments); 
    _db.SaveChanges(); 

    return Ok(reporting); 
} 

Entry()の操作はすべて、エンティティを更新する場合を除いて、あなたのコンテキストでは役に立たないものです。その場合、状態を更新する前に、更新されたエンティティAttach()を更新する必要があります。

さらに、最初の質問に答えるために、EFは既存のトラックを失ってしまったため、新しいAssignmentTypeを追加します。あなたのコントローラはリクエストがヒットするたびに構築されるので、DbContextも毎回構築されます。新しいDbContextを作成するときには、Assignmentなどを返すなど、以前の操作に関する知識はありません(問い合わせ中にAsNoTracking()を指定した場合も同様です)。言い換えれば、エンティティがDbContextによって追跡されない場合、EFはそれを追加しようとします。
これを防ぐには、ナビゲーションプロパティの代わりに外部キーを使用できます(実際にはそうする必要があります)。あるいは、知られているすべてのエンティティをAttach()にすることもできます(ただし、外部キーがある場合は役に立たない)。 ManyToManyリレーションシップでは、新しいエンティティを追加/更新する前にデータベースにクエリを実行する必要があります。そうしないと、ダブリングが発生します。

また、私が「リンクテーブル」と呼ぶものを使用することもできます。あなたの2つのプライマリクラスの間にあるクラスです。 EFは既にManyToManyのすべての関係(データベースをチェックしてください)でそれを行います。 Basicalyが、それが何か行く:その方法で

public class A 
{ 
    public int Id {get; set;} 
    public virtual List<AB> ABs { get; set; } 
} 

public class B 
{ 
    public int Id {get; set;} 
    public virtual List<AB> BAs {get; set; } 
} 

public class AB 
{ 
    public int AId {get;set;} 
    public virtual A {get; set;} 

    public int BId {get;set;} 
    public virtual B {get; set;} 
} 

を、あなただけの残りの世話をしなくて_db.ABs.Add(new AB{AId = 1, BId = 2})で新しいABを追加(または1つを削除)することができます。

+0

if文だけを追加して、それをレポートに追加すると(私の場合のように)、私はまだ同じエラーが表示されます。また、私は新しい課題や更新された課題があるかもしれないことに言及する必要があります。 – adiii4

+0

1つのメソッドで代入を追加または更新することを意味しますか?プラスレポートとコメントを追加する? – Atlasmaybe

+0

はい。ユーザーはウィザードを通過し、最終的にはすべてのデータを含むレポートを保存します。 – adiii4

関連する問題