イメージ エンティティのコレクションを持つレシピ エンティティがあります。私のコントローラーでは、2 つの新しい画像が添付された新しいレシピを保存しようとしています。
_recipeService.Insert(recipe);
try
{
foreach (Image img in recipe.Images)
{
_imageService.Update(img);
}
_recipeService.Save();
バックグラウンドでは、Unit of Work パターンを使用して、すべてのサービスが同じ DbContext を使用していることを確認しています。任意のサービスで Save() を呼び出すと、すべてのエンティティが保存されます。そのため、作成中にレシピに 2 つの画像を添付すると、保存しようとすると次のエラーが発生します。
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;
}
}
}
}