2

Generic Repositories + Unit of work + Entity Framework 5 + Asp.net MVC4 で Ninject で Onion パターンを使用しようとしていますが、EF の "DetectChanges" 機能に問題があり、なぜ必要なのかわかりません。 「偽」に設定します。手伝っていただけませんか?

私の解決策は、次の行を FindingBugContext.cs ファイルのコンストラクターに追加することです。

Configuration.AutoDetectChangesEnabled = false;

次のコードのコメント行で、私の問題をより明確に説明します。これは、私が理解できない問題を再現する非常に単純な (そしておそらくばかげた) コードであり、理解するのは非常に簡単だと思うので、すべてのインターフェイスのコードを含めませんでした。

これは私のサービス クラス「RobotService.cs」です。

public class RobotService : IRobotService
{
    private readonly IRepository<Body> _repoBody;
    private readonly IRepository<BodyPart> _repoBodyPart;
    private readonly IRepository<Robot> _repoRobot;

    private readonly IUnitOfWork _unitOfWork;

    public RobotService(
        IRepository<Body> repoBody,
        IRepository<BodyPart> repoBodyPart,
        IRepository<Robot> repoRobot,
        IUnitOfWork unitOfWork)
    {
        _repoBody = repoBody;
        _repoBodyPart = repoBodyPart;
        _repoRobot = repoRobot;
        _unitOfWork = unitOfWork;
    }

    public Robot Get(int id)
    {
        Robot robot = new Robot();
        robot = _repoRobot.Get(id);

        if (robot != null)
        {
            Body body = _repoBody.Get(robot.BodyId);
            /* FROM NOW ON:
             * robot.BodyId = 0 --> instead of 1: WHY???
             * robot.Name = "Robby1"
             */

            if (body != null)
            {
                BodyPart head = new BodyPart();
                head = _repoBodyPart.Get(body.HeadId);
                body.Head = head;
                /* FROM NOW ON:
                 * body.BodyId = 0 --> instead of 1: WHY???
                 * body.HeadId = 0 --> instead of 1: WHY???
                 * body.LeftArmId = 0 --> instead of 2: WHY???
                 * body.RightArmId = 0 --> instead of 3: WHY???
                 * body.BodyName = "Body1" --> doesn't change
                 */

                BodyPart leftArm = new BodyPart();
                leftArm = _repoBodyPart.Get(body.LeftArmId);
                body.LeftArm = leftArm;

                BodyPart rightArm = new BodyPart();
                rightArm = _repoBodyPart.Get(body.RightArmId);
                body.RightArm = rightArm;

                robot.Body = body;
            }
        }
        return robot;
    }

これは、NuGet パッケージ「Ninject.MVC3」を使用してインストールした後の NinjectWebCommon.cs ファイル内のカスタム コードです。

private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind(typeof(IRepository<>)).To(typeof(RepositoryBase<>)).InRequestScope();
        kernel.Bind<IDbContextFactory>().To<DbContextFactory>().InRequestScope();
        kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
        kernel.Bind<IRobotService>().To<RobotService>();
    }

これは私の DbContext クラス「FindingBugContext.cs」です。

public class FindingBugContext : DbContext
{
    public FindingBugContext()
        : base("FindingBugContext")
    {

        //Configuration.AutoDetectChangesEnabled = false; //This is the solution
    }

    public virtual void Commit()
    {
        base.SaveChanges();
    }

    private IDbSet<Robot> _robots;
    private IDbSet<Body> _bodies;
    private IDbSet<BodyPart> _bodyParts;

    public virtual IDbSet<T> DbSet<T>() where T : class
    {
        return Set<T>();
    }

    public IDbSet<Robot> Robots
    {
        get { return _robots ?? (_robots = DbSet<Robot>()); }
    }

    public IDbSet<Body> Bodies
    {
        get { return _bodies ?? (_bodies = DbSet<Body>()); }
    }

    public IDbSet<BodyPart> BodyParts
    {
        get { return _bodyParts ?? (_bodyParts = DbSet<BodyPart>()); }
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        Database.SetInitializer(new DropCreateFindingBugWithSeedData());

        modelBuilder.Configurations.Add(new RobotConfiguration());
        modelBuilder.Configurations.Add(new BodyConfiguration());
        modelBuilder.Configurations.Add(new BodyPartConfiguration());
    }

    public class DropCreateFindingBugWithSeedData : DropCreateDatabaseAlways<FindingBugContext>
    {
        protected override void Seed(FindingBugContext context)
        {
            BodyPart head = new BodyPart() { Type = PartType.Head, PartName = "Head" };
            BodyPart leftArm = new BodyPart() { Type = PartType.LeftArm, PartName = "LeftArm" };
            BodyPart rightArm = new BodyPart() { Type = PartType.RightArm, PartName = "RightArm" };

            Body body = new Body() { BodyName = "Body1", Head = head, HeadId = 1, LeftArm = leftArm, LeftArmId = 2, RightArm = rightArm, RightArmId = 3 };

            Robot robot = new Robot() { Name = "Robby1", BodyId = 1, Body = body };
            context.Robots.Add(robot);
        }
    }

    public class RobotConfiguration : EntityTypeConfiguration<Robot>
    {
        public RobotConfiguration()
        {
            ToTable("Robots");

            HasKey(r => r.RobotId)
                .Property(r => r.RobotId)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

            HasRequired(r => r.Body)
                .WithMany()
                .HasForeignKey(r => r.BodyId);
        }
    }

    public class BodyConfiguration : EntityTypeConfiguration<Body>
    {
        public BodyConfiguration()
        {
            ToTable("Bodies");

            HasKey(b => b.BodyId)
                .Property(b => b.BodyId)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

            HasRequired(b => b.Head)
                .WithMany()
                .HasForeignKey(b => b.HeadId)
                .WillCascadeOnDelete(false);

            HasRequired(b => b.LeftArm)
                .WithMany()
                .HasForeignKey(b => b.LeftArmId)
                .WillCascadeOnDelete(false);

            HasRequired(b => b.RightArm)
                .WithMany()
                .HasForeignKey(b => b.RightArmId)
                .WillCascadeOnDelete(false);
        }
    }

    public class BodyPartConfiguration : EntityTypeConfiguration<BodyPart>
    {
        public BodyPartConfiguration()
        {
            ToTable("BodyParts");

            HasKey(b => b.BodyPartId)
                .Property(b => b.BodyPartId)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        }
    }
}

これらは私のエンティティです:

public class Robot
{
    public Robot() { Body = new Body(); }

    public int RobotId { get; set; }
    public string Name { get; set; }
    public int BodyId { get; set; }
    public Body Body { get; set; }
}

public class Body { public Body() { Head = new BodyPart(); LeftArm = new BodyPart(); RightArm = new BodyPart(); }

    public int BodyId { get; set; }
    public string BodyName { get; set; }

    public int HeadId { get; set; }
    public BodyPart Head { get; set; }

    public int LeftArmId { get; set; }
    public BodyPart LeftArm { get; set; }

    public int RightArmId { get; set; }
    public BodyPart RightArm { get; set; }
}

public class BodyPart { public int BodyPartId { get; 設定; } public PartType タイプ { get; 設定; } パブリック文字列 PartName { get; 設定; } }

public enum PartType
{
    Head,
    LeftArm,
    RightArm
}

これは作業単位コードです。

public class UnitOfWork : IUnitOfWork
{
    private readonly IDbContextFactory _dbContextFactory;
    private FindingBugContext _context;

    public UnitOfWork(IDbContextFactory dbContextFactory)
    {
        _dbContextFactory = dbContextFactory;
    }

    protected FindingBugContext FindingBugContext
    {
        get { return _context ?? (_context = _dbContextFactory.Get()); }
    }

    public void Commit()
    {
        FindingBugContext.Commit();
    }
}

これは汎用リポジトリ コードです。

public class RepositoryBase<T> : IRepository<T> where T : class
{
    private FindingBugContext _context;
    private readonly IDbSet<T> _dbSet;

    public RepositoryBase(IDbContextFactory dbContextFactory)
    {
        DbContextFactory = dbContextFactory;
        _dbSet = FindingBugContext.Set<T>();
    }

    public IDbContextFactory DbContextFactory
    {
        get;
        private set;
    }

    public FindingBugContext FindingBugContext
    {
        get { return _context ?? (_context = DbContextFactory.Get()); }
    }

    //Read
    public T Get(int id)
    {
        return _dbSet.Find(id);
    }
}

これは私の ContextFactory コードです:

public class DbContextFactory : Disposable, IDbContextFactory
{
    private FindingBugContext _context;

    public FindingBugContext Get()
    {
        if (_context == null)
        {
            _context = new FindingBugContext();
            return _context;
        }
        else
        {
            return _context;
        }
    }

    public void Dispose()
    {
        if (_context != null)
        {
            _context.Dispose();
        }
    }
}
4

0 に答える 0