2

我正在尝试将洋葱模式与通用存储库 + 工作单元 + Entity Framework 5 + Ninject 与 Asp.net MVC4 一起使用,但我遇到了 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; }
}

公共类身体{公共身体(){头=新的身体部分();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; }
}

公共类 BodyPart { 公共 int BodyPartId { 获取;放; } 公共 PartType 类型 { 获取;放; } 公共字符串 PartName { 获取;放; } }

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