web-services - 如何使用 NHibernate 更新新创建的分离实体?

标签 web-services nhibernate serialization session-state entity-relationship

解释:
假设我有一个嵌套多层的对象图,并且每个实体之间都有双向关系。

A -> B -> C -> D -> E
或者换句话说,A收藏了BB引用回 A , 和 B收藏了CC引用回 B , 等等...
现在假设我想为 C 的实例编辑一些数据.在 Winforms 中,我会使用这样的东西:
var instanceOfC;

using (var session = SessionFactory.OpenSession())
{
    // get the instance of C with Id = 3
    instanceOfC = session.Linq<C>().Where(x => x.Id == 3);
}

SendToUIAndLetUserUpdateData(instanceOfC);

using (var session = SessionFactory.OpenSession())
{
    // re-attach the detached entity and update it
    session.Update(instanceOfC);
}
简单来说,我们从数据库中取出一个持久化实例,将其分离,将其交给 UI 层进行编辑,然后重新附加并保存回数据库。
问题:
这适用于 Winform 应用程序,因为我们始终使用相同的实体,唯一的区别是它从持久化到分离再到持久化。
问题是现在我正在使用 Web 服务和浏览器,通过 JSON 数据发送。实体被序列化为字符串,反序列化为 新品 实体。它不再是一个分离的实体,而是一个临时实体,恰好与持久实体(和更新的字段)具有相同的 ID。如果我用这个实体来更新,它会抹去与B的关系。和 D因为它们不存在于这个新的 transient 实体中。
题:
我的问题是,如何通过网络将分离的实体序列化到客户端,接收它们并保存它们,同时保留我没有明确更改的任何关系?我知道 ISession.SaveOrUpdateCopyISession.Merge() (他们似乎做同样的事情?),但是如果我没有明确设置它们,这仍然会消除这些关系。我可以将字段从 transient 实体一一复制到持久实体,但是当涉及到关系时,这不太好,我必须手动处理版本比较。

最佳答案

我通过使用一个中间类来保存来自 Web 服务的数据,然后将其属性复制到数据库实体来解决这个问题。例如,假设我有两个这样的实体:

实体类

public class Album
{
    public virtual int Id { get; set; }
    public virtual ICollection Photos { get; set; }
}

public class Photo
{
    public virtual int Id { get; set; }
    public virtual Album Album { get; set; }
    public virtual string Name { get; set; }
    public virtual string PathToFile { get; set; }
}
Album包含 Photo 的集合对象,以及 Photo有一个回溯到 Album 的引用它在,所以它是一个双向的关系。然后我创建了一个 PhotoDTO类(class):

DTO类
public class PhotoDTO
{
    public virtual int Id { get; set; }
    public virtual int AlbumId { get; set; }
    public virtual string Name { get; set; }
    // note that the DTO does not have a PathToFile property
}

现在假设我有以下 Photo存储在数据库中:

服务器数据
new Photo
{
    Id = 15,
    Name = "Fluffy Kittens",
    Album = Session.Load<Album>(3)
};

客户现在想要更新照片的名称。他们将以下 JSON 发送到服务器:

客户资料

http://server/photos/15
{
    "id": 15,
    "albumid": 3,
    "name": "Angry Kittens"
}

然后服务器将 JSON 反序列化为 PhotoDTO目的。在服务器端,我们更新了 Photo像这样:

服务器代码
var photoDTO = DeserializeJson();
var photoDB = Session.Load(photoDTO.Id); // or use the ID in the URL

// copy the properties from photoDTO to photoDB
photoDB.Name = photoDTO.Name;
photoDB.Album = Session.Load<Album>(photoDTO.AlbumId);

Session.Flush(); // save the changes to the DB

解释

这是我找到的最佳解决方案,因为:
  • 您可以选择允许客户端修改哪些属性。例如,PhotoDTO没有 PathToFile属性,因此客户端永远无法修改它。
  • 您还可以选择是否更新属性。例如,如果客户端没有发送 AlbumId ,它将是 0。您可以检查它而不更改 Album如果 ID 为 0。同样,如果用户不发送 Name ,您可以选择不更新该属性。
  • 您不必担心实体的生命周期,因为它将始终在单个 session 的范围内被检索和更新。

  • 自动映射器

    我建议使用 AutoMapper自动将属性从 DTO 复制到实体,尤其是当您的实体有很多属性时。它省去了您必须手动编写每个属性的麻烦,并且具有很多可配置性。

    关于web-services - 如何使用 NHibernate 更新新创建的分离实体?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2734946/

    相关文章:

    .net - 如何正确修改生成的XSD以克服导致异常 "cs0030:Unable to generate a temporary class"的已知.Net错误

    mysql - 进行数据库备份时网站显示不可用?

    nhibernate - 为新对象分配 ID

    java - 序列化已经有 POJO 的 id (java.lang.String)

    iphone - 实现 Web 服务还是使用脚本进行 iPhone 应用程序交互?

    java - 返回 XML 文档 Jax-WS

    nhibernate - nHibernate限制包含

    c# - xxx 实例的标识符从 y 更改为 z

    Python JSON序列化排除某些字段

    c# - 如何通过 MSMQ(使用 WCF)发送 XDocument?