MVC3、Razor ビュー エンジン、Unit of Work を含むリポジトリ パターンを使用し、EF4.1 Code First を使用してデータ モデルを定義するアプリケーションを構築しています。
ここに背景が少しあります (必要に応じてそれを塗りつぶしてください)。
アプリケーション自体は、単なるイントラネットの「メニュー」です。
2 つの主要なエンティティは、MenuItem と Department です。
- MenuItem は多くの部門を持つことができます
- 部門は多くの MenuItems を持つことができます
- MenuItem は MenuItem を親として持つことができます
これが私のエンティティを定義した方法です
public class MenuItem
{
public int MenuItemId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public virtual ICollection<Department> Departments { get; set; }
public int? ParentId { get; set; }
public virtual MenuItem ParentMenuItem { get; set; }
}
public class Department
{
public int DepartmentId { get; set; }
public string Name { get; set; }
public virtual ICollection<MenuItem> MenuItems { get; set; }
}
FluentAPI を使用して、MenuItem の Self Reference Many-to-Many を定義しています。
私が抱えている問題は、JSON を介してビューに MenuItem を渡すことです。中心的な問題は、組み込みの JSON パーサーが処理できないエンティティ間の循環参照があり、遅延読み込みとプロキシ生成がまだ有効になっていることです。
NugetのJSON.netライブラリをJSONシリアライザーとして使用しています。これは、循環参照の問題を回避する良い方法のようです。プロキシ生成の問題を「修正」する方法がわかりません。現在、シリアライザーはスローしますThe RelationshipManager object could not be serialized. This type of object cannot be serialized when the RelationshipManager belongs to an entity object that does not implement IEntityWithRelationships.
誰でもこれで私を助けることができますか?プロキシ生成をオフにすると、すべての MenuItem の子をロードするのに非常に時間がかかるため、オンのままにしておきます。私はかなりの量を読みましたが、エンティティを別のオブジェクトに投影してそれをシリアル化するなど、さまざまな異なる答えがあるようです。理想的には、JSON.net を設定して RelationshipManager オブジェクトを無視する方法がありますか?
アップデート
これは、JSON.Net シリアライザーのカスタム ContractResolver として使用したものです。これで私の問題は解決したようです。
public class ContractResolver : DefaultContractResolver
{
private static readonly IEnumerable<Type> Types = GetEntityTypes();
private static IEnumerable<Type> GetEntityTypes()
{
var assembly = Assembly.GetAssembly(typeof (IEntity));
var types = assembly.GetTypes().Where(t => String.Equals(t.Namespace, "Namespace", StringComparison.Ordinal));
return types;
}
protected override List<MemberInfo> GetSerializableMembers(Type objectType)
{
if (!AllowType(objectType))
return new List<MemberInfo>();
var members = base.GetSerializableMembers(objectType);
members.RemoveAll(memberInfo => (IsMemberEntityWrapper(memberInfo)));
return members;
}
private static bool AllowType(Type objectType)
{
return Types.Contains(objectType) || Types.Contains(objectType.BaseType);
}
private static bool IsMemberEntityWrapper(MemberInfo memberInfo)
{
return memberInfo.Name == "_entityWrapper";
}
}
IEntity
は、すべての Code First エンティティ オブジェクトが実装するインターフェイスです。