EF保存相关数据

时间:2012-12-07 11:22:54

标签: c# asp.net-mvc design-patterns entity-framework-4

我对EF很陌生,我仍然试图全力以赴 - 我习惯于构建存储过程并调用它们而不是LINQ-SQL,所以请耐心等待!

我正在尝试构建一个其他实体可以关联的简单图像管理器。所以像什么 Entity 1 -has 1-> Image Collection - 有很多 - > Images
Entity 2 -has 1-> Image Collection - 有很多 - > 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 ObjectStateManagerAcceptChanges cannot continue because the object’s key values conflict with another object in the ObjectStateManager.,可能还有其他错误。

编辑1。

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

  1. Controller收到一个ImageCollection实体及其列表 Images根据此问题顶部的模型。就是这样 作为viewmodel(CollectionID和List)

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

  4. 然后,控制器将此ImageCollection传递给服务进行更新。这是我认为有点不对劲的地方,因为我控制器和业务逻辑应该是持久无知的 - 是的我知道我目前正在控制器中通过它的ID开始获取ImageCollection!我可能只是将视图模型传递给服务,或者稍后在线创建消息请求。

  5. 编辑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();
        }
    

    我在哪里这么错? :(谢谢。

1 个答案:

答案 0 :(得分:2)

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

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

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

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

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

这是不正确的。改为使用

Image i = image ;

我希望这很清楚。

根据您的评论进行编辑

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

调试代码并在更新项目之前/之后检查实体密钥以检查其值,只是为了确保它没有更改

enter image description here