34

Code First と Web API で EF を使用しようとしています。多対多の関係をシリアライズするまでは、何の問題もありません。以下の Web API メソッドを実行しようとすると、次のエラー メッセージが表示されます。

public class TagsController : ApiController
{

        private BlogDataContext db = new BlogDataContext();

        // GET api/Tags
        public IEnumerable<Tag> GetTags()
        {
            return db.Tags.AsEnumerable();
        }
}

次のエラーが表示されます。

'System.Data.Entity.DynamicProxies.Tag_FF17EDDE6893000F7672649A39962DB0CA591C699DDB73E8C2A56203ED7C7B6D' with data contract name 'Tag_FF17EDDE6893000F7672649A39962DB0CA591C699DDB73E8C2A56203ED7C7B6D: http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies ' is not expected. DataContractResolver の使用を検討するか、既知の型のリストに静的に認識されていない型を追加します。たとえば、KnownTypeAttribute 属性を使用するか、DataContractSerializer に渡される既知の型のリストにそれらを追加します。

SO の記事 ( article 1article 2 ) を読んだことがありますが、修正は次の属性を追加することです。

[データ契約 (IsReference=true)]

しかし、これは効果がありませんでした。また、[IgnoreDataMember] を使用しても効果はありません。機能しているように見える唯一のオプションは、Configuration.ProxyCreationEnabled を false に設定することです。これは私の唯一のオプションですか?何か不足していますか?

サンプル POCO オブジェクト:

鬼ごっこ

[DataContract(IsReference = true)]
public class Tag
{
        public Tag()
        {
            this.Blogs = new HashSet<Blog>();
        }

        [Key]
        [DataMember]
        public int Id { get; set; }

        [DataMember]
        public string Name { get; set; }

        [IgnoreDataMember]
        public virtual ICollection<Blog> Blogs { get; set; }
}

ブログ

[DataContract(IsReference = true)]
public class Blog
{
    public Blog()
    {
        this.Tags = new HashSet<Tag>();
    }

    [Key]
    [DataMember]
    public int Id { get; set; }

    [DataMember]
    public string Name { get; set; }

    [IgnoreDataMember]
    public virtual ICollection<Tag> Tags { get; set; }
}
4

2 に答える 2

89

次のようなオブジェクトが表示された場合:

System.Data.Entity.DynamicProxies.Tag_FF17EDDE6893000F7672649A39962DB0CA591C699DDB73E8C2A56203ED7C7B6D

これは、通常 POCO オブジェクトと見なされるものへのプロキシのランタイム EF 生成バージョンです。

Entity Framework がこのオブジェクトを作成したのは、オブジェクトがいつ変更されたかを追跡するためです。これにより、呼び出すときに.SaveChanges()何を行うかを最適化できます。これの欠点は、定義した特定のオブジェクトを実際に使用していないことです。そのため、データ コントラクトとフレームワーク (Json.net) は、元の POCO オブジェクトのようにそれらを使用できません。

EF がこのオブジェクトを返さないようにするには、次の 2 つの選択肢があります (ATM)。

まず、DbContext で Proxy オブジェクトの作成をオフにしてみてください

DbContext.Configuration.ProxyCreationEnabled = false;

これにより、特定の DbContext に対するすべてのクエリの Proxy オブジェクトの作成が完全に無効になります。(これはObjectContextのキャッシュされたオブジェクトには影響しません)。

次に、AsNoTracking()EntityFramework 5.0+ を使用 します (ProxyCreationEnabled は EF 5.0 でも引き続き使用できます)。

あなたもできるはずです

DbContext.Persons.AsNoTracking().FirstOrDefault();

また

DbContext.Persons.
  .Include(i => i.Parents)
  .AsNoTracking()
  .FirstOrDefault();

DbContext のプロキシ作成をグローバルに無効にする代わりに、クエリごとに無効にするだけです。(これはObjectContextのキャッシュされたオブジェクトに影響を与えますが、キャッシュされません)

于 2012-10-25T21:34:57.433 に答える
3

プロキシの作成をそのままにしたかったのですが、 を使用するProxyDataContractResolverと問題が解決するように見えました。wcf での使用方法については、 msdnを参照してください。これは正確には WebAPI ではありませんが、正しい道をたどることができるはずです。

于 2014-09-16T13:50:40.297 に答える