1

我对 EF 很陌生,我仍在努力解决这一切——我习惯于构建存储过程并调用它们而不是 LINQ-SQL,所以请耐心等待!

我正在尝试构建一个简单的图像管理器,其他实体可以与之相关。所以像
Entity 1-has 1-> Image Collection-has many-> Images
Entity 2-has 1-> Image Collection-has many->Images等等...

目前我正在尝试做图像收集->图像方面的事情,但是在尝试保存现有数据时遇到了一些非常令人沮丧的问题。
在我的模型上,我有我的业务方法来AddImage收集 ala 上的图像列表

public class ImageCollection : Entity
{
    [Required]
    public string Title { get; set; }
    public virtual ICollection<Image> Images { get; set; }

    public void AddImage(Image Image)
    {
        this.Images.Add(Image);
    }
}

...然后服务会更新集合 - 添加新图像时这一切都很好。

问题是在更新信息时。现在我知道,如果我正在关联信息,如果我处于某种循环中,我可以附加到现有的东西上,例如:

// get tag from context
var image = new Image { Id = 1 } 

// attach into the entity
_service.Attach<Image>(image);

// attach image to collection
collection.Images.Add(image);

但是,当我已经将图像放入其中时collection.Images,我怎么能在数据库中提交/保存我的集合而不尝试复制所有内容?我试过贴...

// attach any previously referenced images so they don't get duplicated
foreach (var image in Collection.Images.Where(image => image.Id > 0).ToList())
{
    Image i = new Image { Id = image.Id };
    (_imageCollectionRepository as GenericRespository<ImageCollection>).Attach<Image>(i);
}

我试过设置它的状态(这是在被调用的内部SetAsUnchangedState<T>(T item){}

_context.Entry<T>(item).State = System.Data.EntityState.Unchanged;

但什么都没有,只是错误,An object with the same key already exists in the ObjectStateManager或者AcceptChanges cannot continue because the object’s key values conflict with another object in the ObjectStateManager.可能还有其他错误。

编辑 1。

我目前正在采取的步骤 - 如果这有帮助......

  1. 控制器接收一个ImageCollection实体及其列表, Images根据此问题顶部的模型。然后将其作为视图模型(CollectionID 和列表)发送到视图

  2. 该视图显示了这些图像及其属性(只是标题),它是主键。然后发布。然后控制器从服务中获取图像集合,ImageCollection collection = _imageService.FindCollectionById(model.CollectionID)并通过业务逻辑将每个图像添加到视图模型中。

  3. 然后控制器将此 ImageCollection 传递给服务进行更新。这就是我认为这一切都有些错误的地方,因为我的控制器和业务逻辑应该是持久性无知的 - 是的,我知道我目前正在通过控制器中的 ID 获取 ImageCollection!我可能只是将视图模型传递给服务,或者稍后创建一个消息请求。

编辑 2 我现在已经找出了哪里出错了,我最终得到了以下代码,目前它并不漂亮,因为我正在努力解决它。但这一切基本上都是正确的吗?或者有没有更有效的方法来做到这一点?

public void UpdateCollection(ViewModels.ImageCollectionViewModel model)
    {
        // get collection
        ImageCollection collection = FindCollectionById(model.CollectionID);

        if (model.Images != null)
        {
            GenericRespository<Image> temp_repository = new GenericRespository<Image>();

            // add images
            foreach (Image i in model.Images)
            {
                if (i.Id > 0)
                {
                    temp_repository.Attach<Image>(i);
                    temp_repository.Update(image);                        
                }
                else
                {
                    collection.Images.Add(i);
                }
            }

            temp_repository.SaveChanges();
        }

        _imageCollectionRepository.Update(collection);
        _imageCollectionRepository.SaveChanges();
    }

我哪里错了?:( 谢谢。

4

1 回答 1

2

在 EF 中,每个实体对象都有一个名为的标识符EntityKey(您可以在运行时看到它的只读值)。因此,例如,当您从数据库中获取 10 个图像时,这些记录中的每一个都将具有不同的唯一键。此 EntityKey 用作这些记录的 ID。

添加新记录时,EntityKey 为空。这允许 DBcontext 知道这是要插入的记录。但是,来自数据库的记录具有 EntityKey 值。

在您的情况下(取决于错误消息),您正在尝试保存现有数据(与数据库数据具有相同的主键)但它们的 entityKey 为空,在这种情况下被视为 DBcontext 中的新记录,但当然会发生冲突与您的数据库数据。

该错误可能是由于您正在创建一个新图像(或列表)来绑定您的图像(或列表),例如

Image i = new Image { Id = image.Id };

这是不正确的。改为使用

Image i = image ;

我希望这很清楚。

根据您的评论进行编辑

附加,不仅获取预先存在的项目,还根据您附加的项目更新其属性。在那个级别,如果您要附加的项目已经存在于 DBContext 中(这是通过比较 EntityKeys 来完成的),那么就可以了。但在您的情况下,它试图附加具有 null EntityKey 的项目(在这种情况下,该项目被视为插入的项目),同时该插入的项目具有另一个项目已经存在的主键(即从技术上讲,数据库中的记录相同,但 EntityKey 不同)。

调试您的代码并在更新项目之前/之后检查实体键以检查其值,以确保它没有更改

在此处输入图像描述

于 2012-12-07T11:44:54.593 回答