I am trying to set up a RestKit object mapping for a rest-like service over what I unfortunately have no control.
The model is a wish list with with a list of products. The WishList and the Product has obviously many-to-many relation. The wish list and the product has various attributes, for simplicity let's suppose that they both have only name.
I have separate services to get the details a wish list, the details of the product, and the relationship between them.
For example:
GET /api/wish_list/?id=1234
{
"name"="My wish list",
"id"=1234
}
GET /api/products
{
products:[
{
"name"="Product 1",
"id"=1111
},
{
"name"="Product 2",
"id"=2222
},
{
"name"="Product 3",
"id"=3333
}]
}
GET /api/wish_list_products/?wish_list_id=1234
{
products:[
{
"id"=1111
},
{
"id"=2222
}
}
I created the core data relationship between the Product and WishList entities but how could I tell to RestKit the fact that it should make a second request to fetch the list of the IDs of the products for a particular WishList?
I guess I should use [RKRoute routeWithRelationshipName:objectClass:pathPattern:method:] and/or RKConnectionDescription object, but I really could not figure out from the help how they could help me in my case.
RestKit won't automatically load the data for the relationship, you need to tell it when to do so. If you add the route using routeWithRelationshipName:objectClass:pathPattern:method: then you can make the request using getObjectsAtPathForRelationship:ofObject:parameters:success:failure:. Basically it makes linking the relationship name to the request to gather the required details.
Related
Say we have something like the standard Book domain object and bookCategory object. In my controller I want to return a subset of list of books to the view. That subset is not achievable using a find query. When I try to filer the return object, it deletes relationships from the database!
I tried this:
class BookCategory{
String name
static hasMany = [books:Book]
}
class Book{
String title
}
def myController() {
def categories
categories = BookCategory.list()
def user = getCurrentUser()
categories.each { category ->
category.books.removeAll { book ->
!isBookBannedForThisUser(book.title, user)
}
[bookCategories: categories]
}
}
The problem is that it permanently removes these books from the categories for all users from the database!!!
I tried putting the method in a service and using a readonly transaction, but this did not help.
I assume that even if I copy all the categories and books into new list, they will still update the DB as they will still have the book IDs (which I need)
Saving to the database when you dont say save() is very dangerous. is there a way to disable this feature completely?
There is a fundamental flaw in your approach. Do not modify your domain instances if you don't intend to have the changes persisted. Doing so is going to cause you headaches.
Your domain model is suppose to be your system of record. Any changes to it are suppose to be persisted.
If you need to gather up data and manipulate it without having it reflected in your domain model then use a DTO (data transfer object) or similar pattern.
Simply calling .discard() will discard the changes you have made from being persisted when the session automatically flushes.
Instead of working against the framework, and disabling behavior, change your approach to be correct.
Say I want to get books by authors who have "john" in their name. How could I do something like:
Book.createCriteria().list(){
like('author.name', '%john%')
}
Assuming that a Book is related to Author you should be able to do the following:
Book.createCriteria().list() {
author {
like('name', '%john%')
}
}
You can read more about Querying Associations in the documentation.
I have a web service that requires a two part query to fully get the information I need. I can query for the list of all vehicles via a GET request to /vehicles.json, which gives me a list of all vehicles like this:
{
vehicles: [
{
vehicle_name: "Sam's Toyota Corola",
uri: ".../vehicle/1001.json"
},
{
vehicle_name: "John's Honda Accord",
uri: ".../vehicle/1002.json"
}
]
}
The uris are the unique ids. Then if I want more information I can query
for the details of a vehicle via a GET request to the vehicle uri, i.e. /vehicle/1001.json, which gives me the details for a vehicle like this:
{
vehicle: {
engine: "V6",
sunroof: "no"
}
}
I'd like to represent a vehicle with one Core Data type that contains: name, uri, engine, and sunroof, but have two routes in RestKit mapped to the same CoreData type, like this:
// Map the list of all vehicles route
[objectManager.router routeClass:[CDVehicle class] toResourcePath:#"/vehicles.json" forMethod:RKRequestMethodGET];
// Map the show of a specific vehicle route
[objectManager.router routeClass:[CDVehicle class] toResourcePath:#"/vehicle/(vehicleID).json" forMethod:RKRequestMethodGET];
RestKit doesn't like this, and gives me an error that there are two routes for the GET method mapped to the same thing. Why?!? Surely this can be done, seeing as how you can do practically anything with RestKit.
Does anyone know how to do this?
This question is kind of old but I googled out your question and a similar one, and the other one has a good answer, just in case you still interested, please refer to this post: How do I have two post routes for the same class in RestKit
They are talking about postObject, but get method in RestKit can also do the same thing.
Can someone explane the following code for me?
public class StoreEditorViewModel
{
public List<Ticket> TotalView { get; set; }
public StoreEditorViewModel()
{
using (MvcTicketsEntities storeDB = new MvcTicketsEntities())
{
var temp = storeDB.Tickets.Include(x => x.Genres).Include(x => x.Artists).ToList();
TotalView = temp.ToList();
}
}
}
I don't understand the Inculde(x => x.genres) *genres is another table in my database. ( i use entity Framework)
The Include is telling EF to fetch the Genres records as part of this sql request, rather than making you call twice (once for Tickets and again for the Tickets Genres).
To quote Jon Galloway in the MVC Music Store example (your code looks very similar)
"We’ll take advantage of an Entity Framework feature that allows us to indicate other related entities we want loaded as well when the Genre object is retrieved. This feature is called Query Result Shaping, and enables us to reduce the number of times we need to access the database to retrieve all of the information we need. We want to pre-fetch the Albums for Genre we retrieve, so we’ll update our query to include from Genres.Include(“Albums”) to indicate that we want related albums as well. This is more efficient, since it will retrieve both our Genre and Album data in a single database request."
Imagine i have the following (this is a search mechanism for my website)
class Supermarket {
String sp_name
String sp_street
}
class Products {
String p_name
String p_price
}
class products_supermarket{
Supermarket sp
Products pro
}
Now i want to create a criteria:
def c = Supermarket.createCriteria()
def results = c.list {
like("sp_street", params.street)
and {
************ ... params.product
}
maxResults(10)
}
Where i have the * i want to be able to find products whithin that supermaked searching on products_supermarket class. How to do that?
PS. If criteria works as an each() method, iterating over all supermarkets, i could use an if-else statment to search for products, and if found i could use: idEq(it), where it is the supermarket id. This way i would make it. My problem is, i dont know how to get current'sm supermarket id. Any help?
and is applied to criterias inside it, so there's no point applying it to a single statement. Top-level criterias are and-ed by defauilt.
You usually better go without connector class, just by using hasMany: Supermarket and hasMany: Product in domain classes. Connector table will be auto-generated by Hibernate.
If you stick with ProductsSupermarket connector class, do add belongsTo: Supermarket and belongsTo: Product to it class, and add 'hasMany: ProductsSupermarket' to other two, or you're losing Grails' GORM advantage.
There's a section "Querying Associations" in the doc.
Object's id is as simple as that: mySupermarket.id, or mySupermarket.ident() if key field is named differently. id field is auto-added to class and table by default.
So the query is:
List<Supermarket> results = Supermarket.withCriteria {
like("sp_street", params.street)
productSupermarket {
product {
idEq(params.product)
}
// or just eq('product', someProduct)
}
************ ... params.product
maxResults(10)
}