111

奇妙なエラーがあります。.NET 4.5 Web API、Entity Framework、および MS SQL Server を試しています。私はすでにデータベースを作成し、正しい主キーと外部キーと関係を設定しました。

.edmx モデルを作成し、Employee と Department の 2 つのテーブルをインポートしました。部門には多くの従業員がいる可能性があり、この関係が存在します。スキャフォールディング オプションを使用して EmployeeController という新しいコントローラーを作成し、Entity Framework を使用して読み取り/書き込みアクションを備えた API コントローラーを作成しました。ウィザードで、従業員をモデルとして選択し、データ コンテキストの正しいエンティティを選択しました。

作成されるメソッドは次のようになります。

public IEnumerable<Employee> GetEmployees()
{
    var employees = db.Employees.Include(e => e.Department);
    return employees.AsEnumerable();
}

/api/Employee 経由で API を呼び出すと、次のエラーが発生します。

「ObjectContent`1」タイプは、コンテンツ タイプ「application/json;」の応答本文をシリアル化できませんでした。...System.InvalidOperationException","StackTrace":null,"InnerException":{"メッセージ":"エラーが発生しました。","ExceptionMessage":"型 'System.Data.Entity.DynamicProxies で検出された自己参照ループ.Employee_5D80AD978BC68A1D8BD675852F94E8B550F4CB150ADB8649E8998B7F95422552'. パス '[0].Department.Employees'.","ExceptionType":"Newtonsoft.Json.JsonSerializationException","StackTrace":" ...

[0].Department.Employees を自己参照しているのはなぜですか? それはあまり意味がありません。データベースに循環参照がある場合、これが発生することが予想されますが、これは非常に単純な例です。何がうまくいかないのですか?

4

13 に答える 13

55

これは、EF オブジェクト コレクションを直接シリアル化しようとしているために発生します。部門には従業員への関連付け、および従業員から部門への関連付けがあるため、JSON シリアライザーは d.Employee.Departments.Employee.Departments などを読み取って無限にループします。

シリアル化の直前にこれを修正するには、必要な小道具を使用して匿名型を作成します

例 (疑似) コード:

departments.select(dep => new { 
    dep.Id, 
    Employee = new { 
        dep.Employee.Id, dep.Employee.Name 
    }
});
于 2013-10-19T15:29:54.050 に答える
8

エラー メッセージは、自己参照ループがあることを意味します。

生成する json は次の例のようになります (1 人の従業員のリストを含む)。

[
employee1 : {
    name: "name",
    department : {
        name: "departmentName",
        employees : [
            employee1 : {
                name: "name",
                department : {
                    name: "departmentName",
                    employees : [
                        employee1 : {
                            name: "name",
                            department : {
                                and again and again....
                            }
                    ]
                }
            }
        ]
    }
}

]

何かを要求するときに、リンクされたすべてのエンティティを取得したくないことを db コンテキストに伝える必要があります。DbContext のオプションはConfiguration.LazyLoadingEnabled

私が見つけた最良の方法は、シリアライゼーションのコンテキストを作成することです:

public class SerializerContext : LabEntities 
{
    public SerializerContext()
    {
        this.Configuration.LazyLoadingEnabled = false;
    }
}
于 2014-09-01T08:04:50.527 に答える
6

使用したいモデルが 1 つしかなかったので、最終的に次のコードになりました。

var JsonImageModel = Newtonsoft.Json.JsonConvert.SerializeObject(Images, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
于 2017-11-01T18:15:51.103 に答える
0

例としての自己参照

public class Employee {
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public int ManagerId { get; set; }
    public virtual Employee Manager { get; set; }

    public virtual ICollection<Employee> Employees { get; set; }

    public Employee() {
        Employees = new HashSet<Employee>();
    }
}
HasMany(e => e.Employees)
    .WithRequired(e => e.Manager)
    .HasForeignKey(e => e.ManagerId)
    .WillCascadeOnDelete(false);
于 2018-07-09T07:54:30.753 に答える
0

ここで説明されているように、各コントローラー/アクションの明示的なサンプルを追加することも検討する場合があります。

http://blogs.msdn.com/b/yaohuang1/archive/2012/10/13/asp-net-web-api-help-page-part-2-providing-custom-samples-on-the-help- page.aspx

つまり、config.SetActualResponseType(typeof(SomeType), "Values", "Get");

于 2014-07-23T21:27:59.467 に答える