OrientDB fails to persist a Vertex, returns ORID but with null vertex eg v(null)[#3:4] - orientdb

I cant get OrientDB to persist an OrientVertex or an oDocument using the java API.
although its works when I use SQL and the OCommand.
trying to persist a vertex with foll code
val factory: OrientGraphFactory = new OrientGraphFactory("plocal:localhost/database", "admin", "admin");
val graph = factory.getTx
val oDocument: ODocument = UserEntityMapper.toODocument(user)
println("ODocument = = "+ oDocument)
val orientVertex = new OrientVertex(graph, oDocument)
println("BEFORE orientVertex = "+ orientVertex)
graph.commit()
println("AFTER orientVertex = "+ orientVertex)
I get debug printouts as
ODocument = {phoneNumber:45435345,email:moses#email.com,dateOfBirth:-766198800000,lastName:Johnson,firstName:Moses,avatarURL:null,loginInfo:{providerID:credentials,providerKey:moses#email.com},userID:a8d96be9-1d09-4e8f-bf8d-6a0d32e1e5aa}
BEFORE orientVertex = v(null)[#3:-2]
AFTER orientVertex = v(null)[#3:4]
As you can see, the vertex is null. Nothing is persisted. I get an ORID that changes the cluster position number.
When I repeat the save the cluster position number is incremented
BEFORE orientVertex = v(null)[#3:-3]
AFTER orientVertex = v(null)[#3:7]
Why does this happen and how can I fix this please? There are no exceptions so i cant tell whats wrong. The cluster/table for User exists on the DB with all teh right fields.
I am using orientdb-community-2.2.0 and Scala.
regards

Sorted it out at last. I was instantiating the ODocument without the class name. In
UserEntityMapper.toODocument(user)
I was doing the equivalent of this
new ODocument(Map("name"->"john", "city" -> "London"))
instead of this
new ODocument("User").fromMap(Map("name"->"john", "city" -> "London"))
So the DB did not pick up the User class.
Thanks actual for pointing me in the right direction

Related

Need clarification about how to apply a custom update to data adapter source

I have created a record-view form that contains a few bound elements via a BindingSource and a BindingNavigator. The viewing of the data fields is operating correctly. Note that the variables da and ds are global in this form.
private void frmItem_Load(object sender, EventArgs e) {
string scon = System.Configuration.ConfigurationManager.ConnectionStrings["myitems"].ToString();
da = new SqlDataAdapter("Select * From myitems where id > 0 ", scon);
ds = new DataSet();
da.Fill(ds);
bindingSource1.DataSource = ds.Tables[0];
bindingNavigator1.BindingSource = this.bindingSource1;
this.txtId.DataBindings.Add(new Binding("Text", bindingSource1, "id", true));
this.txtItem.DataBindings.Add(new Binding("Text", bindingSource1, "item", true));
this.txtUpdatedwhen.DataBindings.Add(new Binding("Text", bindingSource1, "updatedwhen", true));
}
I am showing this record-view form from a data grid view of items by using a row header mouse dbl-click event. The requested row from the dgv is correctly being selected and its row data is correctly being shown in the record-view form.
private void dgvItems_RowHeaderMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e) {
frmItem gfrmItem = new frmItem();
string sID = this.dgvItems.CurrentRow.Cells[0].Value.ToString();
gfrmItem.FilterByID(sID);
gfrmItem.Show();
}
I've added a save button to the navigator so that I can make individual record save. What I'm attempting to do is programatically apply a date/time stamp update before the record is saved from the button click.
private void btnSave_Click(object sender, EventArgs e)
{
this.txtUpdatedwhen.Text = DateTime.Now.ToString();
da.Update(ds);
}
Although the date/time value is changed per the code and shows in the form, the update is not applying the date/time change.
I thought that the textbox value was being bound to the underlying dataset and would accept changes as if I had entered it manually ... but this is not occurring. I had read some other posts that using the data adapter update is the right way to go about this as apposed to doing something like performing a direct sql update.
I'm stumped with how to resolve this. Any pointers would be greatly appreciated.
After letting this sit a while and coming back to it today, I found a resolution.
There was a common misunderstanding at work that I saw in other posts.
That was that the dataadapter does not automatically populate its commands, even if you pass an active connection into the creation step.
So my resolution was to create a global SqlCommandBuilder variable along with the other ones I was using
SqlDataAdapter da;
SqlConnection sc;
SqlCommandBuilder sb;
DataSet ds;
then create the builder object at form load and initialize the update command into a string variable ... which isn't used there after, but the dataadapter commands are now populated.
string scon = System.Configuration.ConfigurationManager.ConnectionStrings["networkadmin"].ToString();
sc = new SqlConnection(scon);
sc.Open();
string sSelect = "Select * From datatable where id > 0 Order By fld1;";
}
this.da = new SqlDataAdapter(sSelect, sc);
sb = new SqlCommandBuilder(da);
// This initiates the commands, though the target var is not used again.
string uCmd = sb.GetUpdateCommand().ToString();
this.ds = new DataSet();
this.da.Fill(this.ds);
Then the update step does work as expected:
this.txtUpdatedwhen.Text = DateTime.Now.ToString();
DataRowView current = (DataRowView)bindingSource1.Current;
current["updatedwhen"] = this.txtUpdatedwhen.Text;
bindingSource1.EndEdit();
this.da.Update(ds);
I hope this helps someone.

OrientDB - exception when I try to save an embeddedlist

I have a class named CalculationFunctionGroup where I have an attribute like this:
List<CalculationFunction> functions;
on my OrientDB I have a table named CalculationFunctionGroup with a property functions definaed as EMBEDDEDLIST and linked class CalculationFunction.
When I try to save an object of type CalculationFunctionGroup an exception raises.
The exception tell me:
The field 'functions' has been declared as EMBEDDEDLIST with linked class 'CalculationFunction' but the record has no class.
I try to find this exception in OrientDB source code, and I find this:
There's a check in ODocument class in the method validateEmbedded where there are these code lines:
if (doc.getImmutableSchemaClass() == null)
throw new OValidationException("The field '" + p.getFullName() + "' has been declared as " + p.getType()
+ " with linked class '" + embeddedClass + "' but the record has no class");
So, I don't understand how can I valued the immutableschemaclass property.
Where I try to set my field value from Java, I use this command line:
this.data.field(fieldName, value, OType.EMBEDDEDLIST);
where data is my ODocument instance, fieldName is functions, value is my List of CalculationFunction and OType is EMBEDDEDLIST.
Used Orient version is 2.2.0
EDIT #1
I try this after Alessandro Rota answer, but the error is the same:
ODocument myEntity = new ODocument("CalculationFunctionGroup");
myEntity.field("referenceItem", object.getReferenceItem().getData());
db.save(myEntity);
db.commit();
In this code snippet I've changed the nature of my objct (the original is a typied object as CalculationFunctionGroup and now is an ODocument). But the error is the same.
Another try I've done, the ODocument myEntity has not attached functions (list of CalculationFunction) but the error raises too
EDIT #2
I've tried with code snippet of Alessandro Rota and works fine.
But when I add as field of CalculationFunction a link field I've the same error! Why?
If I add a link field instead of object.getData() with object.getRawField("#rid") it works fine too.
I don't understand because raises that error message, and the reason of different behaviour when I use only #rid field instead complete object
EDIT #3
Latest news:
This is my test scenario:
I have this table:
CalculationFunction with these property (schemafull):
referenceItem LINK
functions EMBEDDEDLIST
When I try to save, I write this code:
ODocument myGroup = new ODocument("CalculationFunctionGroup");
Object rid = null;
if (object.getField("referenceItem") instanceof RegistryMetadata) {
rid = ((RegistryMetadata)(object.getField("referenceItem"))).getRawField("#rid");
} else if (object.getField("referenceItem") instanceof PayrollRegistryMetadata) {
rid = ((PayrollRegistryMetadata)(object.getField("referenceItem"))).getRawField("#rid");
} else if (object.getField("referenceItem") instanceof PreCalculationMetadata) {
rid = ((PreCalculationMetadata)(object.getField("referenceItem"))).getRawField("#rid");
} else if (object.getField("referenceItem") instanceof CalculationMetadata) {
rid = ((CalculationMetadata)(object.getField("referenceItem"))).getRawField("#rid");
}
myGroup.field("referenceItem", rid, OType.LINK);
myGroup.field("scenario", ((Scenario)object.getField("scenario")).getRawField("#rid"));
List<ODocument> lstFunctions = new ArrayList<ODocument>();
if (object.getField("functions") != null) {
Iterable<ODocument> lstFun = (Iterable<ODocument>) object.getField("functions");
Iterator<ODocument> itFun = lstFun.iterator();
while(itFun.hasNext()) {
ODocument currFun = itFun.next();
ODocument oFun = new ODocument("CalculationFunction");
oFun.field("name", currFun.field("name"));
oFun.field("code", currFun.field("code"));
oFun.field("language", currFun.field("language"));
lstFunctions.add(oFun);
}
}
myGroup.field("functions", lstFunctions, OType.EMBEDDEDLIST);
myGroup.save();
db.commit();
This code goes in error, but... If I write this:
myGroup.field("referenceItem2", rid, OType.LINK);
The code works fine.
The difference: referenceItem is a schemafull property, referenceItem2 is a schemaless field.
You could use this code
ODocument cf1= new ODocument("CalculationFunction");
cf1.field("name","Function 1",OType.STRING);
ODocument cf2= new ODocument("CalculationFunction");
cf2.field("name","Function 2",OType.STRING);
List<ODocument> list=new ArrayList<ODocument>();
list.add(cf1);
list.add(cf2);
ODocument p = new ODocument("CalculationFunctionGroup");
p.field("functions", list, OType.EMBEDDEDLIST);
p.save();
Edit 2
If you want add a link you could use this code
ODocument cf1= new ODocument("CalculationFunction");
cf1.field("name","Function 1",OType.STRING);
ODocument p = new ODocument("CalculationFunctionGroup");
p.field("mylink", cf1, OType.LINK);
p.save();
EDIT 3
I have created schemafull property mylink2
I have used this code
ODocument cf1= new ODocument("CalculationFunction");
cf1.field("name","Function 1",OType.STRING);
cf1.save();
ODocument p = new ODocument("CalculationFunctionGroup");
p.field("mylink", cf1.getIdentity(), OType.LINK);
p.field("mylink2", cf1.getIdentity(), OType.LINK);
p.save();
and I got
Hope it helps.

Cascade save on OrientDB Document API when using embedded types

Given the following test:
// setup
OClass driver = getDatabase().getMetadata().getSchema().createClass(DRIVER);
OClass car = getDatabase().getMetadata().getSchema().createClass(CAR);
car.createProperty(DRIVERS, OType.EMBEDDEDLIST, driver);
OClass team = getDatabase().getMetadata().getSchema().createClass(TEAM);
team.createProperty(CARS, OType.EMBEDDEDSET, car);
// exercise
ODocument alonso = new ODocument(DRIVER).field("name", "Fernando Alonso").field("nationality", "Spanish")
.field("yearOfBirth", 1981);
ODocument button = new ODocument(DRIVER).field("name", "Jenson Button").field("nationality", "british")
.field("yearOfBirth", 1980);
ODocument mp30 = new ODocument(CAR).field(DRIVERS, Arrays.asList(new ODocument[] { alonso, button }));
Set<ODocument> cars = new HashSet<>();
cars.add(mp30);
ODocument mclarenF1Team = new ODocument(TEAM).field(CARS, cars);
mclarenF1Team.save();
// verify
assertEquals(1, getDatabase().countClass(TEAM));
assertEquals(1, getDatabase().countClass(CAR));
assertEquals(2, getDatabase().countClass(DRIVER));
The second assertion fails:
java.lang.AssertionError: expected:<1> but was:<0>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:834)
at org.junit.Assert.assertEquals(Assert.java:645)
at org.junit.Assert.assertEquals(Assert.java:631)
at foo.orientdb.dataaccessapi.StoreJSonIT.testSchemaFull(StoreJSonIT.java:68)
Why does it fail?
The properties CAR and DRIVER are created as embedded list and embedded set, shouldn't a single save in mclarenF1Team do a cascade save for the embedded documents?
Embedded List/Set means that the documents you create will be embedded (Saved) in the parent document and not in his own class/cluster.
IF you want to achieve that behaviour you should use links
See here
http://orientdb.com/docs/2.1/Concepts.html#relationships

Saving to new cluster returns error

I'm creating cluster dynamically in xtend/Java
for (int i : 0 ..< DistributorClusters.length) {
val clusterName = classnames.get(i) + clusterSuffix;
database.command(
new OCommandSQL('''ALTER CLASS «classnames.get(i)» ADDCLUSTER «clusterName»''')).execute();
}
Then I create I add the oRole and Grant the security to the new oRole
val queryOroleCreation = '''INSERT INTO orole SET name = '«clusterSuffix»', mode = 0, inheritedRole = (SELECT FROM orole WHERE name = 'Default')''';
val ODocument result = database.command(new OCommandSQL(queryOroleCreation)).execute();
for (int i : 0 ..< classnames.length) {
database.command(
new OCommandSQL(
'''GRANT ALL ON database.cluster.«classnames.get(i)»«clusterSuffix» TO «clusterSuffix»''')).
execute();
}
Finally I try to save a JsonObject to one of the newly created cluster. I checked in the database and the cluster exists.
val doc = new ODocument();
doc.fromJSON(jsonToSave.toString());
val savedDoc = database.save(doc, "ClassName"+clusterSuffix);
database.commit();
But Orient returns the following error :
SEVERE: java.lang.IllegalArgumentException: Cluster name 'cluster:ClassNameclusterSuffix' is not configured
My Question :
What causes that exception? And can you add values to new cluster created?
Edit
The doc object contains reference to other classes. i.e:
{
#class:"Customer",
#version:0,
name:"Kwik-E-Mart",
user : {
#class:"User",
#version:0,
username: "Apu",
firstName:"Apu",
lastName:"Nahasapeemapetilon"
}
}
The user gets created in the default cluster, but the customer throws the exception.
You should remove the "cluster:" part. The second parameter of the method is "Name of the cluster where to save", it doesn't need any special prefix.
So:
val savedDoc = database.save(doc, "ClassName"+clusterSuffix);
should just work
I find out that using a query works fine source.
The following code worked on the first try:
val query = '''INSERT INTO ClassNameCLUSTER «"ClassName"+clusterSuffix» CONTENT «jsonToSave.toString()»'''
val ODocument savedDoc = database.command(new OCommandSQL(query)).execute();

How to read the unit price of an Item with IPP DevKit

I've seen elsewhere how to set the UnitPrice on an Item, using the wiley and elusive Item1 field as Intuit.Ipp.Data.Qbd.Money. But how do I READ the unit price from the Item1 field? I can't cast it. The new operator doesn't work ("new ...Money(myItem.Item1)"). So how do I get the price?
I realize the DevKit will probably never be changed so this makes sense. But can we at least get some doc explaining all those strange "xxxItemxxx" fields?
ServiceContext context = new ServiceContext(oauthValidator, realmId, intuitServiceType);
DataServices commonService = new DataServices(context);
Intuit.Ipp.Data.Qbd.Item qbdItem = new Intuit.Ipp.Data.Qbd.Item();
Intuit.Ipp.Data.Qbd.Money unitPrice = new Intuit.Ipp.Data.Qbd.Money();
unitPrice.Amount = 22;
unitPrice.AmountSpecified = true;
qbdItem.Item1 = unitPrice;
IEnumerable<Intuit.Ipp.Data.Qbd.Item> qbdItemsResult = commonService.FindAll(qbdItem, 1, 10) as IEnumerable<Intuit.Ipp.Data.Qbd.Item>;
foreach (var itemResult in qbdItemsResult)
{
Intuit.Ipp.Data.Qbd.Money test1UnitPrice = itemResult.Item1 as Intuit.Ipp.Data.Qbd.Money;
}
You can use the above code for .Net.
Response XML of Item entity suggests that 'UntiPrice' is a top level tag.
I tried this usecase using java. PFB code.
QBItemService itemService = QBServiceFactory.getService(context,QBItemService.class);
items = itemService.findAll(context,1, 100);
for (QBItem item : items) {
System.out.println("Name - " + item.getName() + " UnitPrice - " + item.getUnitPrice().getAmount());
Can you please try the same in .Net and let me know if it works in the same way.
Intuit.Ipp.Data.Qbd.Money [ getAmount() ]
Thanks