Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Entity framework 在EF中保存多个子实体会导致键值冲突_Entity Framework_Entity Framework 4 - Fatal编程技术网

Entity framework 在EF中保存多个子实体会导致键值冲突

Entity framework 在EF中保存多个子实体会导致键值冲突,entity-framework,entity-framework-4,Entity Framework,Entity Framework 4,我有一个配方实体,它有一组图像实体。在我的控制器中,我尝试保存一个带有两个新图像的新配方: _recipeService.Insert(recipe); try { foreach (Image img in recipe.Images) { _imageService.Update(img); } _recipeService.Save(); 在后台,我使用工作单元模式来确保所有服务都使用相同的DbContext,对任何服务调用Save()都将保存所有实体。因此,

我有一个配方实体,它有一组图像实体。在我的控制器中,我尝试保存一个带有两个新图像的新配方:

_recipeService.Insert(recipe);

 try
 {
 foreach (Image img in recipe.Images)
 {
      _imageService.Update(img);

 }
 _recipeService.Save();
在后台,我使用工作单元模式来确保所有服务都使用相同的DbContext,对任何服务调用Save()都将保存所有实体。因此,如果在创建过程中将两个图像附加到配方,则在尝试保存时会出现以下错误:

AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges.
我确信这与两个图像实体的ID都为0这一事实有关。这里的最佳实践是什么

FWIW,这是我的首次迁移:

public override void Up()
    {
        CreateTable(
            "dbo.Recipe",
            c => new
                {
                    ID = c.Int(nullable: false, identity: true),
                    CategoryId = c.Int(nullable: false),
                    Title = c.String(),
                    Summary = c.String(),
                    Directions = c.String(),
                    CookingTime = c.Int(nullable: false),
                    CreationDate = c.DateTime(nullable: false),
                    PostedDate = c.DateTime(),
                    LastModifiedDate = c.DateTime(nullable: false),
                    Visible = c.Boolean(nullable: false),
                    TagList = c.String(),
                    Ingredient_ID = c.Int(),
                })
            .PrimaryKey(t => t.ID)
            .ForeignKey("dbo.Category", t => t.CategoryId, cascadeDelete: true)
            .ForeignKey("dbo.Ingredient", t => t.Ingredient_ID)
            .Index(t => t.CategoryId)
            .Index(t => t.Ingredient_ID);

CreateTable(
            "dbo.Image",
            c => new
                {
                    ID = c.Int(nullable: false, identity: true),
                    RecipeId = c.Int(nullable: false),
                    ImageUrl = c.String(nullable: false),
                    MainImage = c.Boolean(nullable: false),
                })
            .PrimaryKey(t => t.ID)
            .ForeignKey("dbo.Recipe", t => t.RecipeId, cascadeDelete: true)
            .Index(t => t.RecipeId);
谢谢

克里斯

编辑:为配方服务添加代码

使用Barbeurian.数据; 使用烤箱模型; 使用制度; 使用System.Collections.Generic; 使用System.Linq; 使用System.Web

public class RecipeService : Service<Recipe>
{
    private IService<Tag> _tagService;

    public RecipeService(IUnitOfWork unitOfWork, IService<Tag> tagService)
    {
        _unitOfWork = unitOfWork;
        _tagService = tagService;
        _repo = _unitOfWork.RecipeRepository;
    }

    public override void Insert(Recipe recipeToCreate)
    {
        List<Tag> tags = new List<Tag>();
        foreach (Tag tag in recipeToCreate.Tags)
        {
            if (_tagService.Get(filter: t => t.Name == tag.Name).Count() > 0)
            {
                tags.Add(_tagService.Get(filter: t => t.Name == tag.Name).SingleOrDefault());
            }
            else
            {
                Tag newTag = new Tag() { 
                    Name = tag.Name
                };

                _tagService.Insert(newTag);
                tags.Add(newTag);
            }
        }

        recipeToCreate.Tags = tags;
        // Validation logic
        if(Validate(recipeToCreate))
            _repo.Insert(recipeToCreate);            
    }

    protected override bool Validate(Recipe recipeToValidate)
    {
        //Ensure recipe has a unique title
        if (_repo.Get(r => r.Title == recipeToValidate.Title).Count() > 0)
            _validationState.AddError("Title", "That title already exists.");

        return _validationState.IsValid;
    }

}
公共类配方服务:服务
{
私人电视服务;
公共配方服务(IUnitOfWork、iSeries服务)
{
_unitOfWork=unitOfWork;
_tagService=tagService;
_回购=_unitOfWork.recipereposition;
}
公共覆盖无效插入(配方recipeToCreate)
{
列表标签=新列表();
foreach(recipeToCreate.Tags中的标记)
{
if(_tagService.Get(filter:t=>t.Name==tag.Name).Count()>0)
{
tags.Add(_tagService.Get(filter:t=>t.Name==tag.Name.SingleOrDefault());
}
其他的
{
Tag newTag=new Tag(){
Name=tag.Name
};
_tagService.Insert(新标签);
添加标签(newTag);
}
}
recipeToCreate.Tags=标签;
//验证逻辑
如果(验证(recipeToCreate))
_回购插入(recipeToCreate);
}
受保护的覆盖布尔验证(配方recipeToValidate)
{
//确保配方具有唯一的标题
if(_repo.Get(r=>r.Title==recipeToValidate.Title).Count()>0)
_validationState.AddError(“标题”,“该标题已存在”);
返回_validationState.IsValid;
}
}
}

这继承自:

public abstract class Service<TEntity> : IService<TEntity> where TEntity : class, IModel 
{
    protected IRepository<TEntity> _repo;
    protected IValidationDictionary _validationState;
    protected IUnitOfWork _unitOfWork;

    public virtual IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, 
        Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, 
        string includeProperties = ""){
        return _repo.Get(filter, orderBy, includeProperties);
    }

    public virtual TEntity GetByID(int id, string includeProperties = ""){
        return _repo.GetByID(id, includeProperties);
    }

    public virtual void Insert(TEntity entity){
        _repo.Insert(entity);
    }

    public virtual void Delete(object id){
        _repo.Delete(id);
    }

    public virtual void Delete(TEntity entity){
        _repo.Delete(entity);
    }

    public virtual void Update(TEntity entity)
    {
        _repo.Update(entity);
    }

    public virtual void Save()
    {
        _unitOfWork.Save();
    }

    public virtual void Dispose()
    {
        _unitOfWork.Dispose();
    }

    protected abstract bool Validate(TEntity entity);

    public IValidationDictionary ValidationState
    {
        get
        {
            return _validationState;
        }
        set
        {
            _validationState = value;
        }
    }
}
}
公共抽象类服务:IService,其中tenty:class,IModel
{
受保护的存款回购;
受保护的IValidationDictionary验证状态;
受保护的工作单元;
公共虚拟IEnumerable Get(表达式筛选器=null,
Func orderBy=null,
字符串includeProperties=“”){
return _repo.Get(过滤器、orderBy、includeProperties);
}
公共虚拟tenty GetByID(int-id,字符串includeProperties=“”){
返回_repo.GetByID(id,包括属性);
}
公共虚拟空白插入(TEntity实体){
_回购插入(实体);
}
公共虚拟无效删除(对象id){
_回购协议删除(id);
}
公共虚拟无效删除(TEntity实体){
_回购。删除(实体);
}
公共虚拟无效更新(TEntity实体)
{
_回购更新(实体);
}
公共虚拟void Save()
{
_unitOfWork.Save();
}
公共虚拟void Dispose()
{
_unitOfWork.Dispose();
}
受保护的抽象布尔验证(TEntity实体);
公共发票验证状态
{
得到
{
返回_validationState;
}
设置
{
_验证状态=值;
}
}
}
}

可能在添加新图像时调用insert

显示\u Recipes服务的实现您是否尝试使用锁来确保您没有以线程方式调用Save,从而导致竞争条件?另外,您真的需要调用所有图像的更新吗?EF不应该遍历树并找到它需要更新的所有实体吗?我希望我可以保持整个操作的事务性。如果一次插入失败,我不想提交操作的任何部分。工作单元保证你可以做任何你想做的事情,只有你调用save操作才会提交Groan。。。我没有注意到我正在调用Update(),而我本应该调用Insert()。谢谢你的到场。