I have a User object with an attribute followingIds (NSArray - transformable core data type) and a relationship followings to-many
Then in restkit i have the following connection description.
When i check the mappingResult objects the followingIds is set but the relationship is not done. The http response provide a user collection with both user objects; the follower and the followed.
(lldb) po [mappingResult.array firstObject]
<AOUser: 0x7feea8ea5940> (entity: AOUser; id: 0xd000000000040000 <x-
coredata://E1732DA6-BAEB-4E6E-BC7D-F0944A2CD5B5/AOUser/p1> ; data: {
userId = 2;
follower = "<relationship fault: 0x7feeade18c80 'follower'>";
followingIds = "(\n 35\n)";
followings = (
);
}
(lldb) po [mappingResult.array lastObject]
<AOUser: 0x7feeadc0bdf0> (entity: AOUser; id: 0xd0000000000c0000 <x-coredata://E1732DA6-BAEB-4E6E-BC7D-F0944A2CD5B5/AOUser/p3> ; data: {
follower = "<relationship fault: 0x7feeade1dae0 'follower'>";
followingIds = "(\n 4\n)";
followings = (
"0xd000000000140000 <x-coredata://E1732DA6-BAEB-4E6E-BC7D-F0944A2CD5B5/AOUser/p5>"
);
userId = 35;
}
EDIT 1:
MApping Code
+ (RKEntityMapping *)mapping
{
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:[self entityName]
inManagedObjectStore:[RKManagedObjectStore defaultStore]];
[entityMapping addAttributeMappingsFromDictionary:#{
#"id": #"userId",
#"followingIds": #"followingIds",
#"username": #"username",
#"email": #"email",
#"profile.pro": #"pro",
#"profile.type": #"type",
#"profile.country": #"countryCode",
#"social.facebook": #"facebook",
#"social.youtube": #"youtube",
#"social.twitter": #"twitter",
#"social.instagram": #"instagram",
#"created": #"timestamp"
}];
entityMapping.identificationAttributes = #[ #"userId" ];
RKRelationshipMapping *relationship = [RKRelationshipMapping relationshipMappingFromKeyPath:#"medias" toKeyPath:#"medias" withMapping:[AOMedia mapping]];
relationship.assignmentPolicy = RKUnionAssignmentPolicy;
[entityMapping addPropertyMapping:relationship];
relationship = [RKRelationshipMapping relationshipMappingFromKeyPath:#"settings" toKeyPath:#"settings" withMapping:[AOSetting mapping]];
relationship.assignmentPolicy = RKUnionAssignmentPolicy;
[entityMapping addPropertyMapping:relationship];
[entityMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"cover" toKeyPath:#"cover" withMapping:[AOMedia mapping]]];
[entityMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"avatar" toKeyPath:#"avatar" withMapping:[AOMedia mapping]]];
[entityMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"stats" toKeyPath:#"stats" withMapping:[AOUserStat mapping]]];
[entityMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"likes" toKeyPath:#"likes" withMapping:[AOLike mapping]]];
[entityMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"favorites" toKeyPath:#"favorites" withMapping:[AOFavorite mapping]]];
[entityMapping addConnectionForRelationship:#"followings" connectedBy:#{#"followingIds": #"userId"}];
[entityMapping setAssignsDefaultValueForMissingAttributes:YES];
return entityMapping;
}
The issue appears to be because followingIds is being stored as a string rather than an array:
followingIds = "(\n 35\n)";
presumably because RestKit can't tell that you want it as an array because it's simply transformable.
You need to update the code so that the followingIds references all state the type as NSArray and then RestKit should hopefully maintain the data type from the JSON and match against a list of foreign ids instead of a single (invalid) id.
Related
I populated a SDT with data in Genexus 15 and need to save it on a transaction. The SDT has a two level structure with header information and detail items.
I tried with this DataProvider but something is wrong, because I get an foreign key violation error when tring to execute it:
Rules:
parm(in: &NewInvoice); // SDT variable
Source:
DPInvoice
{
StampId = &NewInvoice.StampId
InvoiceNumber = &NewInvoice.InvoiceNumber
CustomerId = &NewInvoice.CustomerId
Concept
{
ProductId = &NewInvoice.Concept.CurrentItem.ProductId
ConceptQty = &NewInvoice.Concept.CurrentItem.ConceptQty
}
}
The Event triggering the DP in the webpanel:
&Invoice = DPInvoice(&NewInvoice)
&Invoice.Insert()
commit
This is the transaction structure
This is the SDT Structure
Please help me!
You have to iterate over the second level of &NewInvoice.
Define a variable &NewInvoiceItem of type SDTInvoiceCopy1.ConceptItem in the DataProvider and use the following Source code:
DPInvoice
{
StampId = &NewInvoice.StampId
InvoiceNumber = &NewInvoice.InvoiceNumber
CustomerId = &NewInvoice.CustomerId
Concept Input &NewInvoiceItem in &NewInvoice.Concept
{
ProductId = &NewInvoiceItem.ProductId
ConceptQty = &NewInvoiceItem.ConceptQty
}
}
I have two entities, TestCase and TestCaseStep, defined as follows:
TestCase
#Entity
#Table(name = "TEST_CASE")
public class TestCase implements Serializable, TestCase
{
#Id
#Column(name = "name")
private String name;
#OneToMany(fetch = FetchType.EAGER)
#JoinTable(name = "Testcase_Step_Association", joinColumns = { #JoinColumn(name = "TC_NAME", referencedColumnName = "NAME") }, inverseJoinColumns = {
#JoinColumn(name = "STEP_NAME", referencedColumnName = "NAME") })
#OrderColumn(name = "STEP_NUMBER", nullable = false)
private List<TestCaseStep> testCaseSteps;
[...]
}
TestCaseStep
#Entity
#Table(name = "TEST_CASE_STEPS")
public class TestCaseStep implements Serializable, TestCaseStep
{
#Id
#Column(name = "name")
private String name;
[...]
}
This works fine as long as I do not try to insert the same object into the list of test case steps more than once. As soon as I try that, I get a primary key violation:
Caused by: org.h2.jdbc.JdbcSQLException: Eindeutiger Index oder Prim�rschl�ssel verletzt: "PRIMARY_KEY_9 ON PUBLIC.TESTCASE_STEP_ASSOCIATION(TC_NAME, TESTCASESTEPS_NAME) VALUES ('TESTCASE_1', 'OUT_STEP', 395)"
Unique index or primary key violation: "PRIMARY_KEY_9 ON PUBLIC.TESTCASE_STEP_ASSOCIATION(TC_NAME, TESTCASESTEPS_NAME) VALUES ('TESTCASE_1', 'OUT_STEP', 395)"; SQL statement:
INSERT INTO Testcase_Step_Association (testCaseSteps_NAME, TC_NAME, STEP_NUMBER) VALUES (?, ?, ?) [23505-191]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
at org.h2.message.DbException.get(DbException.java:179)
at org.h2.message.DbException.get(DbException.java:155)
at org.h2.index.BaseIndex.getDuplicateKeyException(BaseIndex.java:107)
at org.h2.mvstore.db.MVSecondaryIndex.checkUnique(MVSecondaryIndex.java:230)
at org.h2.mvstore.db.MVSecondaryIndex.add(MVSecondaryIndex.java:189)
at org.h2.mvstore.db.MVTable.addRow(MVTable.java:704)
at org.h2.command.dml.Insert.insertRows(Insert.java:156)
at org.h2.command.dml.Insert.update(Insert.java:114)
at org.h2.command.CommandContainer.update(CommandContainer.java:98)
at org.h2.command.Command.executeUpdate(Command.java:258)
at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:160)
at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:146)
at com.sun.gjc.spi.base.PreparedStatementWrapper.executeUpdate(PreparedStatementWrapper.java:125)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:892)
... 193 more
I need to allow my users to repeat the same test case step multiple times. How can I accomplish this without using a separate entity to map the relationship by myself?
Instead of defining name as a primary key in both TestCase and TestCaseSteps Entity,try to define a Surrogate Key as a primary key wherein you keep the Generation Strategy of that Surrogate Key to AUTO
In this way ,you always make a new Insert when you are rerunning test cases.
I'm working on a Java project, using Hibernate to administrate data on a SQL database.
I try to fetch a list of instances from the Database, that have a minimal timestamp of the group they share. The group is modeled by a container.
Here is a minimal model sketch:
#Entity
#Table(name = "object")
public class Object implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.Auto)
long obj_id;
#Column(name = "time_stamp", nullable = false)
Date timestamp;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "container_id", nullable = false)
Container con;
}
#Entity
#Table(name = "container")
public class Container{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
long con_id;
#OneToMany(mappedBy = "container")
List<object> obj_list;
}
So there are some objects with a timestamp and containers that group these objects.
For example, there are two containers, con_a and con_b:
Container con_a:
con_id = 1
obj_list = {obj_a, obj_b}
Container con_b:
con_id = 2
obj_list = {obj_c}
And three objects, obj_a, obj_b, obj_c:
Object obj_a
obj_id = 1
timestamp = 10
con = con_a
Object obj_b
obj_id = 2
timestamp = 20
con = con_a
Object obj_c
obj_id = 3
timestamp = 30
con = con_b
The desired List in this example would look like:
List<Object> = {obj_a, obj_c}
I seem to move in a circle, as I do not even know where to "start" the query:
Criteria crit = session.createCriteria(Container.class). ...
or
Criteria crit = session.createCriteria(Object.class). ...
It seems both possible for me, but i just have no idea how to go on from any of those 2 possibilities.
Update [2014.07.11, 14:19]:
I tried and started the query with the Object class and used a Subquery:
Session session = getSession();
Transaction transaction = session.beginTransaction();
DetachedCriteria IdListOfGroupMinimum = DetachedCriteria.forClass(Object.class, "obj")
IdListOfGroupMinimum.createAlias("con.id", "containerId")
.setProjection(
.Projections.projectionList()
.add(Projections.property("obj.id"))
.add(Projections.min("obj.timestamp"))
.add(Projections.groupProperty("containerId")))
.setProjection(Projection.property("obj.id"));
Criteria objects = session.createCriteria(object.class, "obj")
objects.add(Subqueries.in("obj.id", IdListOfGroupMinimum));
List<Object> = objects.list();
But I received the following error:
javax.servlet.ServletException: org.hibernate.QueryException: not an association: id
I tried to do this:
SELECT * from Object
WHERE id IN (
SELECT obj.id
FROM Object obj
INNER JOIN (
SELECT obj.containerID, MIN(obj.timestamp) AS minimum
FROM Object obj
GROUP BY obj.containerID) subquery
ON obj.containerID = subquery.containerID
WHERE obj.timestamp = subquery.minimum
)
I found a solution for my problem which is probably not the most elegant one, but it works.
Mainly I used the SQL-Query that I already posted above:
Session session = getSession();
Transaction transaction = session.beginTransaction();
//This query fetches the IDs of the smallest objects in each group with
//regard to the timestamp
Query q = session.createSQLQuery(
"SELECT obj.id FROM Object obj "
+ "INNER JOIN ( "
+ "SELECT obj.containerID, MIN(obj.timestamp) AS minimum "
+ "FROM Object obj "
+ "GROUP BY obj.containerID) subquery "
+ "ON obj.containerID = subquery.containerID "
+ "WHERE obj.timestamp = subquery.minimum "
);
//This tells Hibernate that the result are values of type Long
q.addScalar("id", LongType.INSTANCE)
//Creates a list of the found IDs
#SuppressWarnings("unchecked")
List<Long> ids = q.list();
//Fetches all object with those IDs...
Criteria smallestOfEachGroup = session.createCriteria(Object.class)
.add(Restrictions.in("id", ids);
//...and saves them in a list.
#SuppressWarnings("unchecked")
List<Object> desiredList = smallestOfEachGroup.list()
try{
transaction.commit();
} catch(HibernateException e) {
transaction.rollback();
}
As all my sketches are not the real code, so there might be still naming errors.
Anyway, I hope this helps someone.
I still would be pleased by any more elegant solution.
Update [2014.07.20, 18:50]:
I found a solution that uses Hibernate Criteria exclusively :)
Session session = getSession();
Transaction transaction = session.beginTransaction();
//This subquery fetches the minimal timestamp of a container.
DetachedCriteria minOfGroup = DetachedCriteria.forClass(Object.class);
minOfGroup.add(Restrictions.eqProperty("con.con_id", "outerObject.con.con_id")
.setProjection(Projections.min("timestamp"));
//This subquery fetches the IDs of all Objects, whose timestamp is minimal
//in their container.
DetachedCriteria groupwiseMin = DetachedCriteria.forClass(Object.class, "outerObject");
groupwiseMin.add(Subqueries.propertyEq("timestamp", minOfGroup));
.setProjections(Projections.id())
//This subquery fetches all Objects whose IDs are fetched by the groupwiseMin
//query
Criteria groupwiseMinObjects = session.createCriteria(Object.class);
groupwiseMinObjects.add(Subqueries.propertyIn("obj_id", groupwiseMin));
List<Object> desiredObjects = groupwiseMinObjects.list();
try{
transaction.commit();
} catch(HibernateException e) {
transaction.rollback();
}
I think you can make this query even shorter, if you remove the groupwiseMinObjects query above replace the groupwiseMin query by:
Criteria anotherGroupWiseMinObjects = session.createCriteria(Object.class, "outerObject");
anotherGroupwiseMinObjects.add(Subqueries.propertyEq("timestamp", minOfGroup));
But I did not test that.
In my original project I use several subqueries that converge in a single query.
That means after some subqueries, there is a final query like:
Criteria finalQuery = session.createCriteria(Object.class);
finalQuery.add(Subqueries. (...) )
(...)
.add(Subqueries. (...) );
I am creating a query inside a function. Everything works fine until this line:
ulist = new query();
Then I get the error:
Could not find the ColdFusion component or interface query.
Code:
//GET USERS LISTS
remote query function getUserLists(userid) {
//CONFIGURE twitter4j
init();
//DEFINE USER LIST QUERY
var userLists = querynew("id, name, member_count", "Integer, VarChar, Integer");
//GET THE USER LISTS
getLists = t4j.getUserLists(#arguments.userid#);
//BUILD THE USER LIST QUERY
for (i=1;i LTE ArrayLen(getLists);i=i+1) {
newRecord = queryAddRow(userLists);
newRecord = querySetCell(userLists, "id", getLists[i].getId());
newRecord = querySetCell(userLists, "name", getLists[i].getName());
newRecord = querySetCell(userLists, "member_count", getLists[i].getMemberCount());
}
//SORT THE USER LIST BY NAME
ulist = new query();
ulist.setDBType("query");
ulist.setAttributes(sourceQuery=userLists);
ulist.setSQL("select * from sourceQuery order by name");
userListsSorted = ulist.execute().getresult();
//RETURN THE SORTED USER LIST QUERY
return userListsSorted;
}
As per Twitter, make sure you have a custom tag path pointing to [instance]/customtags - which should be there by default. You could use a mapping, pointing to one of the subdirectories within that [instance]/customtags directory, eg: /coldfusion pointing to [instance]\CustomTags\com\adobe\coldfusion, then use:
ulist = new coldfusion.query();
// etc
I'd just use the custom tag directory approach though.
Try using the full path:
ulist = new com.adobe.coldfusion.query()
Has anyone had this issue? I am trying to get objects from the database and create a complex poco but I get a cast issue.
The Account property on the poco message type is a poco account type and it will tell me that whatever the first field type is can't be cast to PocoAccount, so in the example below, AccountID is an int so i'll get int cant' be cast to PocoAccount.
var result = (from a in DbAccount.All()
join m in DbMessage.All() on m.AccountID equals a.AccountID
select new PocoMessage {
Account = new PocoAccount {
AccountID = a.AccountID,
FirstName = a.FirstName,
LastName = a.LastName
},
MessageID = m.MessageID,
Subject = m.Subject,
Body = m.Body
});
If found a similar post that suggested using ToList() which seems to fix the issue however it doesn't feel quite right and I haven't checked out the sql consequence.
var result = (from a in DbAccount.All().ToList()
join m in DbMessage.All().ToList() on m.AccountID equals a.AccountID
select new PocoMessage {
Account = new PocoAccount {
AccountID = a.AccountID,
FirstName = a.FirstName,
LastName = a.LastName
},
MessageID = m.MessageID,
Subject = m.Subject,
Body = m.Body
});