13

Entity Frameworkエンティティを、Webプロジェクトおよびデータアクセス層とは別のクラスライブラリに分割しています。私のコントローラーでは、リポジトリを呼び出してを取得し、IEnumerable<RobotDog.Entities.Movie>を使用してjsonにシリアル化しようとしますが、属性JavaScriptSerializerを使用しているにもかかわらず循環参照を取得します。[ScriptIgnore]

重要:当初、私はエンティティ、データアクセス、およびWebをすべて1つのプロジェクトにまとめていましたが、循環参照なしでエンティティを正常にシリアル化することができました。別々のレイヤーを作成したとき、それは私が問題を抱え始めたときです。私はどのエンティティも変更しませんでした。

RobotDog.Entities名前空間内のエンティティの1つの例:

namespace RobotDog.Entities {
    public class Character {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }

        [MaxLength(200)]
        public string Name { get; set; }

        public virtual Person Person { get; set; }

        [ScriptIgnore]
        public virtual Movie Movie { get; set; }
    }
}

私のコントローラー:

namespace RobotDog.Web.Controllers {
    public class MoviesController : Controller {
        private UnitOfWork _unitOfWork = new UnitOfWork();

        [HttpGet]
        public ActionResult Index() {
            var user = Membership.GetUser(User.Identity.Name);
            if(user != null) {
                var movies = _unitOfWork.UserMovieRepository.Get(u => u.UserId == (Guid) user.ProviderUserKey).Select(m => m.Movie);
                var serializer = new JavaScriptSerializer();
                var json = serializer.Serialize(movies);
                return View(json);
            }
            return View();
        }

    }
}

私のリポジトリ:

namespace RobotDog.DataAccess.Movies {
    public class Repository<TEntity> : IRepository<TEntity> where TEntity : class {
        internal MovieContext Context;
        internal DbSet<TEntity> DbSet;

        public Repository(MovieContext context) {
            if (context == null)
                throw new ArgumentNullException("context");

            Context = context;
            DbSet = Context.Set<TEntity>();
        }

        public virtual IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> predicate = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null ) {
            IQueryable<TEntity> query = DbSet;

            if (predicate != null)
                query = query.Where(predicate);

            return orderBy != null ? orderBy(query).ToList() : query.ToList();
        }
    }
}
4

2 に答える 2

25

応答が少し遅いかもしれませんが、EntityFrameworkCode-FirtsのPOCOクラスで同様の問題が発生しました。問題は、プロパティが仮想として宣言されている可能性があることでした。この場合、EFは仮想プロパティをオーバーライドするプロキシクラスを作成します。ScriptIgnore属性は、次のように使用しない限り、デフォルトではオーバーライドされたプロパティに適用されないようです。

[ScriptIgnore(ApplyToOverrides=true)]
于 2013-06-14T12:59:11.317 に答える
9

円形オブジェクトグラフはJSONシリアル化できません。そして、あなたがそれに考え直したとき、それは実際に理にかなっています。これを処理する正しい方法は、ビューモデルを使用することです。ドメインエンティティをビューに直接渡さないでください。公開したい必要なプロパティのみを含むビューモデルを常に定義します。

このJSONを使用するクライアントは、この循環オブジェクトグラフを気にしないと確信しています。したがって、この循環依存関係を破り、必要なプロパティのみを含めるビューモデルを定義するだけです。

次に、ドメインモデルをビューモデルにマップし、このビューモデルをJsonResultに渡すだけです(これはコードのもう1つの問題です。これを委任する代わりに、コントローラーアクションで手動でJSONシリアル化して配管コードを記述しています。枠組み)。

それで:

[HttpGet]
public ActionResult Index() 
{
    var user = Membership.GetUser(User.Identity.Name);
    if(user != null) 
    {
        IEnumerable<Movie> movies = _unitOfWork
            .UserMovieRepository.Get(u => u.UserId == (Guid) user.ProviderUserKey)
            .Select(m => m.Movie);
        IEnumerable<MovieViewModel> moviesVm = ... map the domain model to your view model
        return Json(moviesVm, JsonRequestBehavior.AllowGet);
    }

    // return an empty movies array
    var empty = Enumerable.Empty<MovieViewModel>();
    return Json(empty, JsonRequestBehavior.AllowGet);
}

今注目すべき重要なことはMovieViewModel、クライアントに公開したい情報のみをJSONとして含むクラスを定義することです。すべての循環参照を解除します。他のエンティティをマップするために、このメインビューモデルが参照している追加のビューモデルを自由に用意してください。

そして最も重要なことは、ドメインモデルをビューに渡さないことです。常にビューモデルを定義します。このようにして、アプリケーションは、使用している基盤となるデータアクセステクノロジーから完全に独立しています。このUIはビューモデルで表されるため、UI部分に影響を与えることなく、DALレイヤーを好きなだけ変更できます。

于 2013-01-30T21:14:05.993 に答える