实体框架保存了太多子实体

时间:2014-01-20 21:17:59

标签: c# asp.net .net entity-framework

我是Entity Framework的新手,这也是我第一次在Stack Overflow上发帖,请跟我一起去。

我正在开发一个由多个对象组成的项目,我希望将其保存到我的数据库中。我正在使用单个上下文和一系列存储库类来访问它们。

当我尝试保存实体时,它似乎保存了与其关联的所有虚拟实体,即使该实体已存在于数据库中也是如此。

这些是我的课程:

public class Requirement
{
    public int ID { get; set; }
    public DateTime DateDue { get; set; }
    public DateTime DateCompleted { get; set; }

    public virtual Standard Standard { get; set; }
    public virtual Project Project { get; set; }
}

public class Standard
{
    public int ID { get; set; }
    public int AgencyID { get; set; }
    public string Name { get; set; }

    public virtual Agency Agency { get; set; }
}


public class Project
{
    public int ID { get; set; }
    public bool Active { get; set; }

    public virtual Agency Agency { get; set; }
    public virtual Department Department { get; set; }
}

这是我创建一些数据的方法:

public class RequirementRepository
{
    public static string CreateMockData()
    {
        StandardRepository stdRep = new StandardRepository();
        ProjectRepository projRep = new ProjectRepository();
        RequirementRepository reqRep = new RequirementRepository();
        Project project = projRep.Find(1);
        StringBuilder sb = new StringBuilder()
        foreach (Standard s in stdRep.FindByAgencyID(project.Agency.ID))
        {
            Requirement r = new Requirement();
            r.Project = project;
            r.Standard = s;
            r.DateCompleted = (DateTime)SqlDateTime.MaxValue;
            r.DateDue = DateTime.Now.AddDays(90);

            r = reqRep.Save(r);

            sb.AppendLine(String.Format("Saved Requirement ID {0} with Project ID {1}<br>", r.ID, r.Project.ID));
        }

        return sb.ToString();
    }
}

这里是关联的存储库代码:

public class ProjectRepository
{
    public Project Find(int id)
    {
        using (var db = new MyContext())
        {
            return db.Projects
                .Include(p => p.Agency)
                .Include(p => p.Department)
                .First(p => p.ID.Equals(id));
        }
    }
}


public class StandardRepository
{
    public List<Standard> FindByAgencyID(int agencyID)
    {
        using (var db = new MyContext())
        {
            return db.Standards.Where(r => r.AgencyID == agencyID).ToList();
        }
    }
}



public class RequirementRepository
{
    public Requirement Save(Requirement requirement)
    {
        using (var db = new MyContext())
        {
            Requirement retVal = requirement;
            if (requirement.ID.Equals(0))
            {
                retVal = db.Requirements.Add(requirement);
            }
            else
            {
                db.Entry(requirement).State = EntityState.Modified;
            }

            db.SaveChanges();
            return retVal;
        }
    }
}

当我运行这个方法时,我希望它能够在数据库中插入一些新的需求,项目ID为1,标准ID为其标准ID。相反,它为它添加的每个需求创建一个全新的项目和一个全新的标准,然后将这些ID分配给需求。

我和我的导师(他也是Entity Framework的新手)非常困惑,我似乎无法在其他地方找到任何相关信息。我希望有人可以帮忙。

提前致谢!

2 个答案:

答案 0 :(得分:0)

每个上下文都会跟踪加载,修改的实体和添加的实体。

您的存储库需要看起来像这样......

public class StandardRepository
{
    MyContext _context;

    public StandardRepository(MyContext context)
    {
        _context = context;
    }

    public List<Standard> FindByAgencyID(int agencyID)
    {
        return _context.Standards.Where(r => r.AgencyID == agencyID).ToList();
    }
}

public class RequirementRepository
{
    MyContext _context;

    public RequirementRepository(MyContext context)
    {
        _context = context;
    }

    public Requirement Save(Requirement requirement)
    {
    Requirement retVal = requirement;
    if (requirement.ID.Equals(0))
    {
        retVal = _context.Requirements.Add(requirement);
    }
    else
    {
        _context.Entry(requirement).State = EntityState.Modified;
    }

    _context.SaveChanges();
    return retVal;
    }
}

public class RequirementRepository
{
    public static string CreateMockData()
    {
        using(MyContext context = new MyContext())
        {
                StandardRepository stdRep = new StandardRepository(context);
                ProjectRepository projRep = new ProjectRepository(context);
                RequirementRepository reqRep = new RequirementRepository(context);
                Project project = projRep.Find(1);
                StringBuilder sb = new StringBuilder()
                foreach (Standard s in stdRep.FindByAgencyID(project.Agency.ID))
                {
                Requirement r = new Requirement();
                r.Project = project;
                r.Standard = s;
                r.DateCompleted = (DateTime)SqlDateTime.MaxValue;
                r.DateDue = DateTime.Now.AddDays(90);

                r = reqRep.Save(r);

                sb.AppendLine(String.Format("Saved Requirement ID {0} with Project ID {1}<br>", r.ID, r.Project.ID));
            }
        }
        return sb.ToString();
    }
}

答案 1 :(得分:0)

根据我的理解,您不必手动设置已修改对象的状态,除非您已从其上下文中分离它。 EF跟踪对象状态。

我喜欢用这样的东西:

    public abstract class EntityRepositoryBase<TEntity> : IDisposable, IEntityRepositoryBase<TEntity> where TEntity : class , IEntityWithId
    {
        protected EntityRepositoryBase()
        {
            Context = new SomeEntities();
        } 

        public abstract ObjectSet<TEntity> EntityCollection { get; }
        public SomeEntities Context { get; set; }

        public TEntity GetById(int id)
        {
            return EntityCollection
                .FirstOrDefault(x => x.Id == id);
        }

    public void Dispose()
    {
        Context.Dispose();
    }
}

然后在派生存储库中:

public class AnswerRepository : EntityRepositoryBase<AnswerEntity>, IAnswerRepository
{
    public override ObjectSet<AnswerEntity> EntityCollection
    {
        get { return Context.AnswerEntities; }
    }
}

我使用ninject将存储库注入到相关的类中,但是你应该能够得到类似的:

using (var repo = new AnswerRepository()) 
{ 
// modifying via Context
var someEntity = repo.GetById(someId);
someEntity.Value = "1";
repo.Context.SaveChanges();

//modifying via repo
repo.Delete(anotherEntity);
}

然后做你需要做的事。如果需要执行存储库外修改,然后在存储库中执行SaveChanges()以及任何特定的CRUD类型方法,则通过接口IEntityRepositoryBase公开上下文。一旦超出范围,对象和底层连接将被关闭。

相关问题