从多个 DTO 构造域对象

发布于 2024-07-08 08:23:10 字数 873 浏览 8 评论 0原文

假设您有规范的 Customer 域对象。 您可以在三个不同的屏幕上显示客户:外部管理、内部管理和更新帐户。

进一步假设每个屏幕仅显示 Customer 对象中包含的所有数据的子集。

问题是:当 UI 从每个屏幕(例如通过 DTO)传回数据时,它仅包含完整客户域对象的子集。 因此,当您将该 DTO 发送到 Customer Factory 以重新创建 Customer 对象时,您只有 Customer 的一部分。

然后,您将该客户发送到客户存储库以保存它,并且一堆数据将被清除,因为它不在那里。 悲剧随之而来。

所以问题是:你会如何处理这个问题?

我的一些想法:

  • 包括一个论点 存储库指示哪一部分 客户更新,并忽略 其他人

  • 当您加载 Customer 时,将其保存在静态内存中、会话中或任何地方,然后当您从 UI 收到 DTO 之一时,仅更新与 DTO 相关的部分

(IMO),这两者都是拼凑。 还有其他更好的想法吗?

@chadmyers:这就是问题所在。

实体具有属性 A、B、C 和 D。DTO

#1 包含 B 和 C 的属性。DTO

#2 包含 C 和 D 的属性。UI

要求 DTO #1,您从存储库加载实体,将其转换为 DTO #1,只填写B和C,然后交给UI。

现在 UI 更新 B 并将 DTO 发回。 您重新创建实体,它只填充了 B 和 C,因为这是 DTO 中包含的全部内容。

现在您想要保存仅填充了 B 和 C 的实体,而 A 和 D 为空/空白。 存储库无法知道是否应该将 A 和 D 持久更新为空白,或者是否应该忽略它们。

Suppose you have the canonical Customer domain object. You have three different screens on which Customer is displayed: External Admin, Internal Admin, and Update Account.

Suppose further that each screen displays only a subset of all of the data contained in the Customer object.

The problem is: when the UI passes data back from each screen (e.g. through a DTO), it contains only that subset of a full Customer domain object. So when you send that DTO to the Customer Factory to re-create the Customer object, you have only part of the Customer.

Then you send this Customer to your Customer Repository to save it, and a bunch of data will get wiped out because it isn't there. Tragedy ensues.

So the question is: how would you deal with this problem?

Some of my ideas:

  • include an argument to the
    Repository indicating which part of
    the Customer to update, and ignore
    others

  • when you load the Customer, keep it in static memory, or in the session, or wherever, and then when you receive one of the DTOs from the UI, update only the parts relevant to the DTO

IMO, both of these are kludges. Are there any other better ideas?

@chadmyers: Here is the problem.

Entity has properties A, B, C, and D.

DTO #1 contains properties for B and C.

DTO #2 contains properties for C and D.

UI asks for DTO #1, you load entity from the repository, convert it into DTO #1, filling in only B and C, and give it to the UI.

Now UI updates B and sends the DTO back. You recreate the entity and it has only B and C filled in because that is all that is contained in the DTO.

Now you want to save the entity, which has only B and C filled in, with A and D null/blank. The repository has no way of knowing if it should update A and D in persistence as blanks, or whether it should ignore them.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

转瞬即逝 2024-07-15 08:23:10

我将使用工厂在收到 DTO 后从存储库加载完整的客户对象。 之后,您只能更新 DTO 中指定的那些字段。

例如,这还允许您通过检查上次更新的时间戳来对客户应用一些乐观并发。

I would use factory to load a complete customer object from repository upon receipt of DTO. After that you can update only those fields that were specified in DTO.

That also allows you to apply some optimistic concurrency on your customer by checking last-updated timestamp, for example.

后eg是否自 2024-07-15 08:23:10

这是一个网络应用程序吗? 从存储库加载客户对象,从 DTO 更新它,然后保存回来。 对我来说,这似乎并不像是一个拼凑。 :)

更新:根据您的更新(A、B、C、D 示例)

所以我的想法是,当您加载实体时,它已填写 A、B、C 和 D。如果仅 DTO#1更新B& C,没关系。 A 和 D 不受影响(这是期望的情况)。

存储库对 B& 有何作用? C的更新由他决定。 例如,如果您使用 Hibernate/NHibernate,它只会找出并发布更新。

只是因为 DTO #1 只有 B & C 并不意味着您必须同时取消 A 和 C 。 D. 别打扰他们。

Is this a web app? Load the customer object from the repo, update it from the DTO, save it back. That doesn't seem like a kludge to me. :)

UPDATE: As per your updates (the A, B, C, D example)

So what I was thinking is that when you load the entity, it has A, B, C, and D filled in. If DTO#1 only updates B & C, that's OK. A and D are unaffected (which is the desired situation).

What the repository does with the B & C updates is up to him. If you're using Hibernate/NHibernate, for example, it will just figure it out and issue an update.

Just because DTO #1 only has B & C doesn't mean you have to also null out A & D. Just leave them alone.

天荒地未老 2024-07-15 08:23:10

起初我错过了这个问题的要点,因为它是基于一些我认为从设计角度来看没有意义的事情。

  1. 从存储库中提取实体,然后将其转换为 DTO 是浪费精力。 我假设您的 DAL 将 DTO 传递到您的存储库,然后存储库将其转换为完整的实体对象。 因此,将其转换回 DTO 似乎很浪费。

  2. 如果您的搜索结果页面显示大量记录并且仅显示部分实体数据,则拥有多个 DTO 是有意义的。 在这种情况下,仅传递该页面所需的数据是有效的。 将包含部分数据的 DTO 传递到 CRUD 页面是没有意义的。 只需给它一个完整的 DTO 甚至一个完整的实体对象即可。 如果它不使用所有数据,那很好,不会造成任何损害。

所以主要问题是我认为您不应该使用部分 DTO 将数据传递到这些页面。 如果您使用完整的 DTO,则每当执行保存操作时,我都会执行以下 3 个步骤:

  1. 从存储库或数据库中提取完整的 DTO 使用
  2. 通过表单所做的任何更改更新 DTO
  3. 将完整的 DTO 保存回存储库或

数据库方法需要额外的数据库命中,但这对于 CRUD 表单来说确实不是一个重要问题。

I missed the point of this question at first because it is predicated on a few things that I don't think make sense from a design perspective.

  1. Hydrating an entity from repository and then converting it to a DTO is a waste of effort. I assume that your DAL passes a DTO to your repository which then converts it to a full entity object. So converting it back to a DTO seems wasteful.

  2. Having multiple DTOs makes sense if you have a search results page that shows a high volume of records and only displays part of your entity data. In that case it's efficient to pass that page just the data it needs. It does not make sense to pass a DTO that contains partial data to a CRUD page. Just give it a full DTO or even a full entity object. If it doesn't use all of the data, fine, no harm done.

So that main problem is that I don't think you should pass data to these pages using partial DTOs. If you used a full DTO, I would do the following 3 steps whenever the save action is performed:

  1. Pull the full DTO from repository or db
  2. Update the DTO with any changes made through the form
  3. Save the full DTO back to the repository or db

This method requires an extra db hit but that's really not a significant issue on a CRUD form.

挽梦忆笙歌 2024-07-15 08:23:10

如果我们知道存储库(几乎专门)处理非常丰富的域实体,那么您的众多 DTO 就可以简单地映射回来。

即,

dtoUser.MapFrom<In,Out>(Entity)
or
dtoAdmin.MapFrom<In,Out>(Entity)

您可以执行相反的操作,将 dto 信息返回给实体,依此类推。 因此,您的存储库仅保存丰富的实体而不是大量的 DTO。DTO

entity.Foo = dtoUser.Foo
or
entity.Bar = dtoAdmin.Bar

entityRepsotiry.Save(entity) <-- do not pass DTO.

的全部要点是使演示变得简单,或者说对于 WCF 数据传输,它与存储库或实体无关。

此外,您永远不应该从 DTO 构造实体...获取实体的唯一两种方法分别是通过工厂(新)或存储库(现有)。

您提到将实体存储在某个地方,为什么要这样做? 这就是你的存储库的工作。 它将决定从哪里获取实体(数据库、缓存等),无需将其存储在其他地方。

希望有助于在您的领域分配职责,这始终是一个挑战,并且到处都有灰色区域,但总的来说,这些是存储库、DTO 等的典型用途

If we have an understanding that a Repository handles (almost exclusively) very rich domain Entity, then you numerous DTO's could simply map back.

i.e.

dtoUser.MapFrom<In,Out>(Entity)
or
dtoAdmin.MapFrom<In,Out>(Entity)

you would do the reverse to get the dto information back to the Entity and so on. So your repository only saves rich Entity's NOT numerous DTO's

entity.Foo = dtoUser.Foo
or
entity.Bar = dtoAdmin.Bar

entityRepsotiry.Save(entity) <-- do not pass DTO.

The whole point of DTO's is to keep things simple for the presentation or say for WCF dataTransfer, it has nothing to do with the Repository or the Entity for that matter.

Furthermore, you should never construct an Entity from DTO's... the only two ways to ever acquire an Entity is through a Factory(new) or a Repository(existing) respectively.

You mention storing the Entity somewhere, why would you do this? That is the job of your repository. It will decide where to get the Entity(db,cache,e.t.c), no need to store it somewhere else.

Hope that helps assign responsibility in your domain, it is always a challenge and there are gray area's here and there but in general, these are the typical uses of Repository, DTO e.t.c.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文