如何使用 NHibernate 更新新创建的分离实体?
说明:
假设我有一个嵌套了多个级别的对象图,并且每个实体彼此之间具有双向关系。
A -> B -> C -> D -> E
或者换句话说,A
具有 B
的集合,并且 B
具有对 A
的引用,并且 < code>B 有一个 C
的集合,而 C
有一个对 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
的关系,因为它们不存在于这个新的瞬态实体中。
问题:
我的问题是,如何通过网络将分离的实体序列化到客户端、接收它们并保存它们,同时保留我没有明确更改的任何关系?我知道 ISession.SaveOrUpdateCopy
和 ISession.Merge()
(它们似乎做同样的事情?),但如果我不这样做,这仍然会消除关系明确设置它们。我可以将字段从瞬态实体一一复制到持久实体,但这在关系方面效果不太好,我必须手动处理版本比较。
Explanation:
Let's say I have an object graph that's nested several levels deep and each entity has a bi-directional relationship with each other.
A -> B -> C -> D -> E
Or in other words, A
has a collection of B
and B
has a reference back to A
, and B
has a collection of C
and C
has a reference back to B
, etc...
Now let's say I want to edit some data for an instance ofC
. In Winforms, I would use something like this:
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);
}
In plain English, we grab a persistent instance out of the database, detach it, give it to the UI layer for editing, then re-attach it and save it back to the database.
Problem:
This works fine for Winform applications because we're using the same entity all throughout, the only difference being that it goes from persistent to detached to persistent again.
The problem is that now I'm using a web service and a browser, sending over JSON data. The entity gets serialized into a string, and de-serialized into a new entity. It's no longer a detached entity, but rather a transient one that just happens to have the same ID as the persistent one (and updated fields). If I use this entity to update, it will wipe out the relationship to B
and D
because they don't exist in this new transient entity.
Question:
My question is, how do I serialize detached entities over the web to a client, receive them back, and save them, while preserving any relationships that I didn't explicitly change? I know about ISession.SaveOrUpdateCopy
and ISession.Merge()
(they seem to do the same thing?), but this will still wipe out the relationships if I don't explicitly set them. I could copy the fields from the transient entity to the persistent entity one by one, but this doesn't work too well when it comes to relationships and I'd have to handle version comparisons manually.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我通过使用中间类来保存来自 Web 服务的数据,然后将其属性复制到数据库实体来解决这个问题。例如,假设我有两个实体,如下所示:
实体类
Album
包含Photo
对象的集合,并且Photo
具有对它所在的Album
,因此它是双向关系。然后,我创建一个PhotoDTO
类:DTO 类
现在假设我在数据库中存储了以下
Photo
:服务器数据
客户端现在想要更新照片的名称。他们将以下 JSON 发送到服务器:
客户端数据
PUT http://server/photos/15
然后服务器将 JSON 反序列化为
PhotoDTO
对象。在服务器端,我们像这样更新照片
:服务器代码
说明
这是我找到的最佳解决方案,因为:
您可以选择允许客户端修改哪些属性。例如,
PhotoDTO
没有PathToFile
属性,因此客户端永远无法修改它。您还可以选择是否更新属性。例如,如果客户端未发送
AlbumId
,则该 ID 将为 0。您可以检查这一点,如果 ID 为 0,则不要更改Album
。同样,如果用户没有发送Name
,您可以选择不更新该属性。您不必担心实体的生命周期,因为它始终会在单个会话的范围内检索和更新。
AutoMapper
我建议使用 AutoMapper 自动将属性从 DTO 复制到实体,特别是如果您的实体有很多属性的属性。它省去了您手动编写每个属性的麻烦,并且具有很多可配置性。
I solved this problem by using an intermediate class to hold data coming in from the web service, then copying its properties to the database entity. For example, let's say I have two entities like so:
Entity Classes
Album
contains a collection ofPhoto
objects, andPhoto
has a reference back to theAlbum
it's in, so it's a bidirectional relationship. I then create aPhotoDTO
class:DTO Class
Now let's say I have the following
Photo
stored in the database:Server Data
The client now wants to update the photo's name. They send over the following JSON to the server:
Client Data
PUT http://server/photos/15
The server then deserializes the JSON into a
PhotoDTO
object. On the server side, we update thePhoto
like this:Server Code
Explanation
This was the best solution I've found because:
You can choose which properties the client is allowed to modify. For example,
PhotoDTO
doesn't have aPathToFile
property, so the client can never modify it.You can also choose whether to update a property or not. For example, if the client didn't send over an
AlbumId
, it will be 0. You can check for that and not change theAlbum
if the ID is 0. Likewise, if the user doesn't send over aName
, you can choose not to update that property.You don't have to worry about the lifecycle of an entity because it will always be retrieved and updated within the scope of a single session.
AutoMapper
I recommend using AutoMapper to automatically copy the properties from the DTO to the entity, especially if your entites have a lot of properties. It saves you the trouble of having to write every property by hand, and has a lot of configurability.