我对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 ObjectStateManager
或AcceptChanges cannot continue because the object’s key values conflict with another object in the ObjectStateManager.
,可能还有其他错误。
编辑1。
我正在采取的步骤 - 如果这有帮助...
Controller收到一个ImageCollection
实体及其列表
Images
根据此问题顶部的模型。就是这样
作为viewmodel(CollectionID和List)
视图显示这些图像及其属性(仅标题)和
这是主要的关键。然后发布。然后,控制器从服务ImageCollection collection = _imageService.FindCollectionById(model.CollectionID)
获取图像集合,并通过业务逻辑在视图模型中添加每个图像。
然后,控制器将此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();
}
我在哪里这么错? :(谢谢。
答案 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)。
调试代码并在更新项目之前/之后检查实体密钥以检查其值,只是为了确保它没有更改