通过 Web 传输实体框架对象并通过 JSON 返回的最佳方式

Posted

技术标签:

【中文标题】通过 Web 传输实体框架对象并通过 JSON 返回的最佳方式【英文标题】:Best way to transfer an Entity Framework object over the web and back via JSON 【发布时间】:2011-01-11 00:50:30 【问题描述】:

我有一些 MVC 代码将 EF 3.5 对象序列化为匿名类型,以作为 JSON 结果返回到我页面上的 AJAX 调用。我遇到的障碍是,当我通过 JSON 将对象发送回服务器时(并让 ModelBinder 将它反序列化为我的 EF 类型),我必须在我的实体框架上下文中更新它手动。或者至少这就是我现在正在做的事情。它没有 EntityKey,因此附加它失败。我最终不得不查找旧对象并逐个属性更新它。有什么想法吗?将 EntityKey 与我的对象一起传递的解决方案是什么?

这是我所拥有的:

    public void Update(Album album)
    
        using (var db = new BandSitesMasterEntities())
        
            var albumToUpdate = db.Album.First(x => x.ID == album.ID);

            albumToUpdate.AlbumTitle = album.AlbumTitle;
            albumToUpdate.Description = album.Description;
            albumToUpdate.ReleaseYear = album.ReleaseYear;
            albumToUpdate.ImageURL = album.ImageURL;
            albumToUpdate.OtherURL = album.OtherURL;

            db.SaveChanges();
        
    

这就是我想做的事情或类似的事情

    public void Update(Album album)
    
        using (var db = new BandSitesMasterEntities())
        
            db.Attach(album)
            db.SaveChanges();
        
    

【问题讨论】:

为什么不使用数据服务? @ashraf,他说他正在使用 EF 3.5 【参考方案1】:

或者您可以使用 AutoMapper 为您映射这些字段,因此您只需在示例中添加一行。

【讨论】:

实际上是 2 行 - 检索密钥然后映射。【参考方案2】:

为什么不直接使用 UpdateModel 或 TryUpdateModel 控制器方法呢?它与 EF 配合得非常好,您甚至可以显式设置包含的属性列表。

id 参数将通过 MVC 框架自动映射到表单上指定 id 的隐藏字段。

public void Update(int id, FormCollection collection)

    using (var db = new BandSitesMasterEntities())
    
        var albumToUpdate = db.Album.First(x => x.ID == id);

        //use UpdateModel to update object, or even TryUpdateModel
        UpdateModel(albumToUpdate, new string[]  "AlbumTitle", "Description", "ReleaseYear", "ImageURL", "OtherURL" );

        db.SaveChanges();
    

【讨论】:

【参考方案3】:

在 EF 4.0 中,这对我们来说变得容易多了。这就是我们在 EF 3.5 中所做的:

public static void AttachAsModified(this ObjectContext objectContext, string setName, object entity,
                                    IEnumerable<String> modifiedFields)

    objectContext.AttachTo(setName, entity);
    ObjectStateEntry stateEntry = objectContext.ObjectStateManager.GetObjectStateEntry(entity);
    foreach (String field in modifiedFields)
    
        stateEntry.SetModifiedProperty(field);
    

然后:

using (var db = new BandSitesMasterEntities())

    db.AttachAsModified("Album", album, new string[]  "AlbumTitle", "Description", "ReleaseYear", "ImageURL", "OtherURL" )
    db.SaveChanges();

如果你有外键约束会变得更复杂,但看起来你没有。

【讨论】:

【参考方案4】:

没有办法解决实体密钥问题。您要么必须将其添加到您的匿名类型,要么我建议您将代码移植到使用数据服务。

http://www.hanselman.com/blog/jQueryToShipWithASPNETMVCAndVisualStudio.aspx

这将允许您在客户端执行所有数据库操作。

http://msdn.microsoft.com/en-us/data/bb931106.aspx

【讨论】:

【参考方案5】:

您是否尝试过类似的方法:

object original;
var key = contexte..CreateEntityKey("EntitySet", modified);
if(contexte.TryGetObjectByKey(key, out original))

    var originalEntity = (YourEntityType)original;
    // You have to mannualy set your entityKey
    originalEntity.YourEntityReference.EntityKey = new EntityKey("Entities.EntitySet", "Id", modified.YourEntity.Id);

    contexte.ApplyPropertyChanges("EntitySet", modified);

contexte.SaveChanges();

假设你的 EntityReference 是由 dropDown 设置的,你仍然有 Id

【讨论】:

【参考方案6】:

在您的 Album 实体的分部类中,您可以定义一个 CopyFrom 函数并从您的 Update 函数中调用它

partial class Album

   public void CopyFrom(Album album)
   
   //individual field copying here
   



 public void Update(Album album) 
     
      ...
      albumToUpdate.CopyFrom(album);
      ...
    

【讨论】:

以上是关于通过 Web 传输实体框架对象并通过 JSON 返回的最佳方式的主要内容,如果未能解决你的问题,请参考以下文章

将对象插入核心数据实体时处理重复项

首先通过将类型作为参数传递来动态实例化实体框架数据库中的模型对象

实体框架查询性能

设计模式-传输对象模式

尝试通过实体框架更新数据库对象时对象已存在错误

如何使用实体框架通过 id 删除对象