primaria llave foranea compuesta clave agregar rest asp.net-web-api composite-key asp.net-web-api-routing attributerouting

llave - Servicio REST de recursos de clave compuesta



llave compuesta oracle (2)

También me gusta la estética de /api/Products/1/Parts/2 . También puede hacer que varias rutas vayan a la misma acción, así que podría duplicar y también ofrecer /api/Parts/2/Products/1 como una URL alternativa para el mismo recurso.

En cuanto a POST, ya conoces la clave compuesta. Entonces, ¿por qué no eliminar la necesidad de POST y simplemente usar PUT para la creación y las actualizaciones? La POST a una URL de recursos de colección es excelente si su sistema genera la clave principal, pero en los casos en los que tiene un compuesto de claves primarias ya conocidas, ¿por qué necesita POST?

Dicho esto, también me gusta la idea de tener un ProductPartAssocController separado para contener las acciones para estos URL. Tendría que hacer un mapeo de rutas personalizado, pero si está usando algo como AttributeRouting.NET es muy fácil de hacer.

Por ejemplo, hacemos esto para administrar usuarios en roles:

PUT, GET, DELETE /api/users/1/roles/2 PUT, GET, DELETE /api/roles/2/users/1

6 URL, pero solo 3 acciones, todas en GrantsController (llamamos al gerundio entre usuarios y roles una "Otorgamiento"). La clase termina buscando algo como esto, usando AttributeRouting.NET :

[RoutePrefix("api")] [Authorize(Roles = RoleName.RoleGrantors)] public class GrantsController : ApiController { [PUT("users/{userId}/roles/{roleId}", ActionPrecedence = 1)] [PUT("roles/{roleId}/users/{userId}", ActionPrecedence = 2)] public HttpResponseMessage PutInRole(int userId, int roleId) { ... } [DELETE("users/{userId}/roles/{roleId}", ActionPrecedence = 1)] [DELETE("roles/{roleId}/users/{userId}", ActionPrecedence = 2)] public HttpResponseMessage DeleteFromRole(int userId, int roleId) { ... } ...etc }

Esto me parece un enfoque bastante intuitivo. Mantener las acciones en un controlador separado también hace que los controladores sean más ágiles.

Me he encontrado con un problema en el trabajo donde no puedo encontrar información sobre el estándar habitual o la práctica para realizar operaciones CRUD en un servicio web RESTful contra un recurso cuya clave principal es un compuesto de otros identificadores de recursos. Estamos utilizando MVC WebApi para crear los controladores. Por ejemplo, tenemos tres tablas:

  • Product : PK = ProductId
  • Part : PK = PartId
  • ProductPartAssoc : PK = (ProductId, PartId)

Un producto puede tener muchas partes y una parte puede ser un componente de muchos productos. La tabla de asociación también contiene información adicional relevante para la asociación en sí misma de la que necesita ser editable.

Tenemos las clases ProductsController y PartsController que manejan las operaciones GET / PUT / POST / DELETE usuales usando plantillas de ruta definidas como: {controller}/{id}/{action} manera que los siguientes IRIs funcionen:

  • GET, POST /api/Products : devuelve todos los productos, crea un nuevo producto
  • GET, PUT, DELETE /api/Products/1 - recupera / actualiza / elimina el producto 1
  • GET, POST /api/Parts : devuelve todas las partes, crea una nueva parte
  • GET, PUT, DELETE /api/Parts/2 - recupera / actualiza / elimina la parte 2
  • GET /api/Products/1/Parts - obtenga todas las partes para el producto 1
  • GET /api/Parts/2/Products : obtenga todos los productos para los cuales la parte 2 es un componente

Donde estoy teniendo problemas es en cómo definir la plantilla de ruta para los recursos ProductPartAssoc. ¿Cómo deberían ser la plantilla de ruta y el IRI para obtener los datos de asociación? Siguiendo la convención, esperaría algo como:

  • GET, POST /api/ProductPartAssoc : devuelve todas las asociaciones, crea una asociación
  • GET, PUT, DELETE /api/ProductPartAssoc/[1,2] - recupera / actualiza / elimina la asociación entre el producto 1 y la parte 2

Sin embargo, a mis colegas les parece que esto es estéticamente desagradable y parecen pensar que sería mejor no tener una clase ProductPartAssocController , sino agregar métodos adicionales al ProductsController para administrar los datos de asociación:

  • GET, PUT, DELETE /api/Products/1/Parts/2 - obtenga datos para la asociación entre el producto 1 y la parte 2 en lugar de datos para la parte 2 como miembro de la parte 1, lo que convencionalmente sería el caso basado en otros ejemplos tal como /Book/5/Chapter/3 que he visto en otros lugares.
  • POST No hay ninguna pista aquí sobre cómo esperan que se vea el IRI. Desafortunadamente, ellos son los que toman las decisiones.

Al final del día, supongo que lo que busco es una validación o una dirección que pueda señalar y decir "Mira, esto es lo que hacen los demás".

¿Cuál es la práctica típica para tratar con los recursos identificados por claves compuestas?


Yo sugiero:

  • POST /api/PartsProductsAssoc : Crear enlace entre la parte y el producto. Incluir identificadores de piezas y productos en datos POST.
  • GET, PUT, DELETE /api/PartsProductsAssoc/<assoc_id> : lea / actualice / elimine el enlace con <assoc_id> (no es parte de la identificación del producto, sí, esto significa crear una nueva columna en su tabla PartsProductsAssoc).
  • GET /api/PartsProductsAssoc/Parts/<part_id>/Products : obtenga una lista de productos asociados con la parte dada.
  • GET /api/PartsProductsAssoc/Products/<product_id>/Parts : obtenga una lista de las partes asociadas con el producto dado.

Razones para adoptar este enfoque:

  • URI único y completo para cada enlace.
  • La modificación de un enlace modifica un único recurso REST.

Para obtener más información, consulte https://www.youtube.com/watch?v=hdSrT4yjS1g a las 56:30.