c# - Convenciones de nomenclatura DTO, modelado y herencia
nhibernate (3)
¿Qué uso para insertar y actualizar?
Las operaciones de servicio generalmente se definen en relación muy estrecha con las operaciones comerciales. El lenguaje de negocios no habla en términos de "inserciones" y "actualizaciones", ni tampoco los servicios.
Es probable que el servicio de administración de clientes tenga alguna operación de
Register
que tome el nombre del cliente y tal vez algunos otros parámetros opcionales.
¿Puedo crear otro DTO?
Sí, deberías crear otro DTO.
A veces, el contrato de operación de servicio puede ser suficiente y no es necesario definir un DTO separado para una operación en particular:
function Register(UserName as String, Address as Maybe(of String)) as Response
Pero la mayoría de las veces es mejor definir una clase DTO separada incluso para una sola operación de servicio:
class RegisterCommand
public UserName as String
public Address as Maybe(of String)
end class
function Register(Command as RegisterCommand) as Response
RegisterCommand
DTO de RegisterCommand
puede parecer muy similar al DTO de CustomerWithAddress
porque tiene los mismos campos, pero en realidad estos 2 DTO tienen significados muy diferentes y no se sustituyen entre sí.
Por ejemplo, CustomerWithAddress
contiene AddressDetails
, mientras que una simple representación de dirección String
puede ser suficiente para registrar un cliente.
Usar un DTO separado para cada operación de servicio toma más tiempo para escribir pero es más fácil de mantener.
Estamos creando una aplicación web utilizando AngularJS, C #, ASP.Net Web API y Fluent NHibernate. Hemos decidido utilizar DTO para transferir datos a la capa de presentación (vistas angulares). Tuve algunas dudas con respecto a la estructuración general y el nombramiento de DTOs. Aquí hay un ejemplo para ilustrar mi escenario. Digamos que tengo una entidad de dominio llamada Cliente que se parece a:
public class Customer
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual Address Address { get; set; }
public virtual ICollection<Account> Accounts { get; set; }
}
Ahora, en mi capa de vistas / presentación necesito recuperar diferentes tipos de Cliente como:
1) Just Id y Name 2) Id, Name y dirección 3) Id, Name, dirección y cuentas
He creado un conjunto de DTO para lograr esto:
public class CustomerEntry
{
public int Id { get; set; }
public string Name { get; set; }
}
public class CustomerWithAddress : CustomerEntry
{
public AddressDetails Address { get; set; }
}
public class CustomerWithAddressAndAccounts : CustomerWithAddress
{
public ICollection<AccountDetails> Accounts { get; set; }
}
AddressDetails y AccountDetails son DTO que tienen todas las propiedades de sus entidades de dominio correspondientes.
Esto funciona bien para consultas y recuperación de datos; la pregunta es qué uso para las inserciones y actualizaciones. Durante la creación de un nuevo registro de cliente, el nombre y la dirección son obligatorios y las cuentas son opcionales. En otras palabras, necesito un objeto con todas las propiedades del cliente. De ahí la confusión:
1) ¿Qué uso para insertar y actualizar? El DTO CustomerWithAddressAndAccounts tiene todo lo que contiene, pero su nombre parece un poco incómodo de usar para insertar / actualizar.
2) ¿Creo otro DTO ... si lo hago, no sería una duplicación, ya que el nuevo DTO será exactamente como CustomerWithAddressAndAccounts?
3) Por último, pero no menos importante, ¿la estructura de herencia DTO descrita anteriormente parece ser una buena opción para el requisito? ¿Hay alguna otra manera de modelar esto?
He revisado otras publicaciones sobre este tema, pero no he podido avanzar mucho. Una cosa que hice fue evitar el uso del sufijo "DTO" en los nombres de clase. Creo que se siente un poco superfluo.
Me encantaría conocer tu opinión
Gracias
A partir de su artículo 1, para inserciones y actualizaciones es mejor usar el patrón de Comando. Según CQRS, no necesita DTO. Considera este esquema: a través de blogs.msdn.com
La recomendación es que solo debe tener una clase DTO para cada entidad con el sufijo DTO, por ejemplo, CustomerEntryDTO
para la entity
del Customer
(pero ciertamente puede usar jerarquías de herencia según la elección y los requisitos).
Además, agregue una clase base de DTOBase
abstracta o una interfaz; y no utilice estas jerarquías de herencia profunda para cada dirección, cuenta y otras propiedades que se incluirán en las DTO secundarias. En su lugar, incluya estas propiedades en la misma clase CustomerEntryDTO
(si es posible) como se muestra a continuación:
[Serializable]
public class CustomerEntryDTO : DTOBase, IAddressDetails, IAccountDetails
{
public int Id { get; set; }
public string Name { get; set; }
public AddressDetails Address { get; set; } //Can remain null for some Customers
public ICollection<AccountDetails> Accounts { get; set; } //Can remain null for some Customemer
}
Además, sus DTO deben ser serializables para pasar a través de los límites del proceso.
Para más información sobre el patrón DTO, consulte los siguientes artículos:
Objeto de transferencia de datos
Edición: en caso de que no desee enviar ciertas propiedades por el cable (sé que lo necesitaría condicionalmente, por lo que necesitaría explorar más sobre esto), puede excluirlas del mecanismo de serialización mediante el uso de atributos como No NonSerialized
( pero funciona solo en campos y no en propiedades, consulte el artículo de solución alternativa para usar con propiedades: No se ha serializado en propiedad ). También puede crear su propio atributo personalizado, como ExcludeFromSerializationAttribute
y aplicarlo a las propiedades que no desea enviar cada vez por cable según determinadas reglas / condiciones. Ver también: serialización XML condicional.
Edición 2: use interfaces para separar las diferentes propiedades en la clase CustomerEntryDTO
. Consulte el principio de segregación de interfaz en Google o MSDN. Intentaré poner una explicación de ejemplo más tarde.