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

时间:2013-03-29 15:55:52

标签: entity-framework entity-framework-4

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

_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);

谢谢,

克里斯

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

使用Barbecurian.Data; 使用Barbecurian.Models; 使用系统; 使用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;
    }

}

}

这继承自:

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;
        }
    }
}
}

1 个答案:

答案 0 :(得分:0)

也许在添加新图片时调用insert