Extraction et actualisation des données avec REST

Le protocole OData requiert que toutes les entités soient adressables à partir de leur forme canonique. Cela signifie que chaque entité doit inclure la clé de l'entité racine partitionnée, la racine de schéma.

Voici un exemple de la manière d'utiliser l'association à partir d'une entité racine pour définir l'adresse d'un enfant dans :
/Customer('ACME')/order(100)

Dans WCF Data Services, l'entité enfant doit être directement adressable, c'est-à-dire que la clé dans la racine du schéma doit faire partie de la clé de l'enfant : /Order(customer_customerId='ACME', orderId=100). L'on y parvient en créant une association à l'entité racine dans laquelle l'association un-à-un ou plusieurs-à-un à l'entité racine est également identifiée comme une clé. Lorsque des entités sont incluses comme faisant partie de la clé, les attributs de l'entité parent sont exposés comme propriétés de la clé.

Figure 1. Schéma des entités Customer et Order
Schéma des entités Customer et Order

Le schéma des entités Customer/Order illustre la manière dont chaque entité est partitionnée à l'aide de Customer. L'entité Order inclut Customer comme partie de sa clé et elle est donc directement accessible. Le service de données REST expose toutes les associations de clés comme des propriétés individuelles : Order a customer_customerId et OrderDetail a order_customer_customerId and order_orderId.

L'API EntityManager permet de trouver la commande avec l'ID du client et celui de la commande :

transaction.begin();
// L'on recherche l'Order à l'aide du Customer.  Nous n'incluons que l'Id
// dans la classe Customer lorsqu'on génère l'instance de clé OrderId.
Order order = (Order) em.find(Order.class, 
    new OrderId(100, new Customer('ACME')));
...
transaction.commit();
Lorsqu'on utilise le service de données REST, la commande peut être extraite avec l'une des URL :
  • /Order(orderId=100, customer_customerId='ACME')
  • /Customer('ACME')/orders?$filter=orderId eq 100

L'adresse de la clé Customer est créée avec l'attribut name de l'entité Customer, un caractère de soulignement et l'attribut name de l'ID Customer : customer_customerId.

Une entité peut également inclure une entité non racine comme faisant partie de sa clé si tous les ancêtres de cette entité non racine ont des associations de clés à la racine. Dans notre exemple, OrderDetail a une association de clés à Order et Order a une association de clés à l'entité Customer racine. Avec l'API EntityManager :

transaction.begin();
// L'on construit une instance de clé OrderDetailId.  Elle inclut
// Order et Customer avec uniquement le jeu de clés. 
Customer customerACME = new Customer("ACME");
Order order100 = new Order(100, customerACME);
OrderDetailId orderDetailKey = 
    new OrderDetailId(order100, "COMP");
OrderDetail orderDetail = (OrderDetail) 
    em.find(OrderDetail.class, orderDetailKey); 
...

Le service de données REST permet l'adressage direct d'OrderDetail :

/OrderDetail(productId=500, order_customer_customerId='ACME', order_orderId =100)

L'association partant de l'entité OrderDetail vers l'entité Product a été rompue pour permettre le partitionnement indépendant des commandes et du stock de produits. L'entité OrderDetail stocke la catégorie et l'ID de produit au lieu d'une relation en dur. En découpant les deux schémas d'entités, il n'est accédé qu'à une seule partition à la fois.

Le schéma Category et Product montre que l'entité racine est Category et que chaque Product a une association à une entité Category. L'entité Category est incluse dans l'identité Product. Le service de données REST expose une propriété de clé : category_categoryId qui permet l'adressage direct de Product.

Category étant l'entité racine, dans un environnement partitionné, Category doit être connu pour que Product puisse être trouvé. Avec l'API EntityManager, la transaction doit être fixée à l'entité Category avant toute recherche de Product.

Avec l'API EntityManager :

transaction.begin();
// L'on crée l'entité racine Category avec uniquement la clé.  Cela
// nous permet de construire un ProductId sans avoir besoin de trouver
// d'abord la Category.  La transaction est à présent fixée 
// à la partition où est stockée la Category "COMP".
Category cat = new Category("COMP");
Product product = (Product) em.find(Product.class, 
    new ProductId(500, cat)); 
...

Le service de données REST permet l'adressage direct de Product :

/Product(productId=500, category_categoryId='COMP')