How to create a constraints, indexes and nodes in a single procedure/plugin call? - neo4j

similarly the code is for creating indexes and millions of nodes the respective methods. This is for creating fresh DB from JSON file.
I encounter the following error:
Exception: Cannot perform data updates in a transaction that has performed schema updates. Simple begin transaction and close it doesn't work?
After some time the session crashes in CreateNodes() method?
How exactly we separate the schema creation and data update?
Also refer the question I have posted before trying to get the similar answer, but no success. (I tried both injecting GraphDatabaseService as well as with Bolt Driver the result is the same).
How to use neo4j bolt session/transaction in a procedure as plugin for neo4j server extension?
for (int command = 4; command < inputNeo4jCommands.size(); command++) {
log.info(inputNeo4jCommands.get(command));
NEO4JCOMMANDS cmnd = NEO4JCOMMANDS.valueOf(inputNeo4jCommands.get(command).toUpperCase());
log.info(NEO4JCOMMANDS.valueOf(inputNeo4jCommands.get(command).toUpperCase()).toString());
if (NEO4JCOMMANDS.CONSTRAINT.equals(cmnd)) {
CreateConstraints1();
}
if (NEO4JCOMMANDS.INDEX.equals(cmnd)) {
CreateIndexes();
}
if (NEO4JCOMMANDS.MERGE.equals(cmnd)) {
log.info("started creating nodes........");
CreateNodes();
}
}
private void CreateIndexes1() {
log.info("Adding indexes.....");
log.info("into started adding index ......");
try (Transaction tx = db.beginTx()) {
log.info("got a transaction .....hence started adding index ......");
Iterator<Indx> itIndex = json2neo4j.getIndexes().iterator();
while (itIndex.hasNext()) {
Indx indx = itIndex.next();
Label lbl = Label.label(indx.getLabelname());
Iterable<IndexDefinition> indexes = db.schema().getIndexes(lbl);
if (indexes.iterator().hasNext()) {
for (IndexDefinition index : indexes) {
for (String key : index.getPropertyKeys()) {
if (!key.equals(indx.getColName())) {
db.schema().indexFor(lbl).on(indx.getColName());
}
}
}
} else {
db.schema().indexFor(lbl).on(indx.getColName());
}
tx.success();
tx.close();
}
log.info("\nIndexes Created..................Retured the method call ");
}
}

A lot of context is missing from your question and code examples, so it's hard to give a definite answer. Where is the exception thrown in the code example? There's no CreateNodes() method, so we can't find out why it's failing (Out Of Memory Error due to a transaction too large?).
However, there's an issue with your transaction management in the CreateIndexes1() method (not following the Java naming conventions, by the way):
try (Transaction tx = db.beginTx()) {
// ...
while (/* ... */) {
// ...
tx.success();
tx.close();
}
}
You're closing the transaction multiple times, when it's actually in a try-with-resources block where you don't need to close it yourself at all:
try (Transaction tx = db.beginTx()) {
// ...
while (/* ... */) {
// ...
}
tx.success();
}
I guess json2neo4j is the deserialization of a JSON describing the indices to create on labels. The logic is flawed: you try to create an index for a property as soon as you find an index for another property, when you should find out if an index for the current property exists and only create the index if it's missing then.
for (Indx indx : json2neo4j.getIndexes()) {
Label lbl = Label.label(indx.getLabelname());
boolean indexExists = false;
for (IndexDefinition index : db.schema().getIndexes(lbl)) {
for (String property : index.getPropertyKeys()) {
if (property.equals(indx.getColName())) {
indexExists = true;
break;
}
}
if (indexExists) {
break;
}
}
if (!indexExists) {
db.schema().indexFor(lbl).on(indx.getColName());
}
}

Related

Dart streams error with .listen().onError().onDone()

I have an issue with some code that looks like this. In this form I have an error
The expression here has a type of 'void', and therefore can't be used.
Try checking to see if you're using the correct API; there might be a function or call that returns void you didn't expect. Also check type parameters and variables which might also be void.dart(use_of_void_result).
If I remove the .onDone() the error goes away. Why? ELI5 please :-)
I was looking at https://api.dart.dev/stable/2.7.0/dart-async/Stream/listen.html but seem to still be misundertanding something.
I also read https://api.dart.dev/stable/2.7.0/dart-async/StreamSubscription/onDone.html
serviceName.UploadThing(uploadRequest).listen((response) {
uploadMessageOutput = response.message;
if (response.uploadResult) {
showSuccess();
} else {
showError();
}
getUploadFileList(event);
isSaveInProgress = false;
}).onError((error) {
isSaveInProgress = false;
_handleFileUploadError(uploadRequest, error);
}).onDone(() {
isSaveInProgress = false;
});
Your code is almost right, but will only require a simple change to work correctly.
You would be seeing the same error if you swapped the ordering of onError and onDone, so the issue has nothing to do with your stream usage. However, you're attempting to chain together calls to onError and then onDone which won't work since both of these methods return void.
What you're looking for is cascade notation (..), which will allow for you to chain calls to the StreamSubscription returned by listen(). This is what your code should look like:
serviceName.UploadThing(uploadRequest).listen((response) {
uploadMessageOutput = response.message;
if (response.uploadResult) {
showSuccess();
} else {
showError();
}
getUploadFileList(event);
isSaveInProgress = false;
})..onError((error) { // Cascade
isSaveInProgress = false;
_handleFileUploadError(uploadRequest, error);
})..onDone(() { // Cascade
isSaveInProgress = false;
});

Grails manual transactions and rollback

I'm trying to implement the following scenario:
class A {
...
static hasMany = [bees: B]
}
class B {
static belongsTo = [a: A]
}
Now, we create about 10,000 instances of B (from a service) that belongs to an A at a time, but if 1 fails it should roll back all the successfully created ones. I have tried a few methods, none worked:
try {
for (int i = 0; i < batch.numToMake; i++) {
def b = new B().save(flush: i % 1000 == 0)
if (i == 50) {
throw new RuntimeException("simulate")
}
}
batch.status = Constants.BATCH_STATUS_DONE
batch.save(flush: true)
} catch (e) {
// This was a last resort test and still did not work
batch.status = Constants.BATCH_STATUS_FAILED
batch.vouchers.each {
batch.removeFromVouchers(it)
}
batch.save(flush: true)
}
// This did not work at all
B.withTransaction { status ->
try {
for (int i = 0; i < batch.numToMake; i++) {
def b = new B().save(flush: i % 1000 == 0)
if (i == 50) {
throw new RuntimeException("simulate")
}
}
} catch (e) {
status.setRollbackOnly()
}
}
Can anyone help out how I can create large volumes of a item in the hasMany / belongsTo relationship, but roll back everything on fail of 1, from a service class.
Your service needs to be transactional (put grails #Transactional annotation on top of the service class), then you don't need to try/catch. Any RuntimeException thrown from the method will trigger a transaction rollback.
So you can simply do the following:
def import() {
def a = A.get(1L)
for (int i = 0; i < 1000; i++) {
new B(a: a).save()
// runtime exception thrown here would rollback everything
}
}
What you need to take care of when working with batches is to make sure that the session does not grow too large. You can prevent that by getting a handle to the current session and then flush and clear it:
def import() {
Parent.withSession { session ->
def a = A.get(1L)
for (int i = 0; i < 10000; i++) {
new B(a: a).save()
// runtime exception thrown here would rollback everything
if (i % 100 == 0) {
session.flush()
session.clear()
}
// runtime exception thrown here would rollback everything
}
}

Common way to execute a stored proc from both ColdFusion and Railo

I think I've gotten the most simplest scenario built. I just want to pass it by everyone for a sanity check. Here's the idea:
GetErrorCodes.cfm does the following:
<cfscript>
response = new ErrorCodes().WhereXXX(); // ACF or Railo, doesn't matter
</cfscript>
ErrorCodes.cfc:
function WhereXXX() {
return new sproc().exec('app.GetErrorCodes'); // All my functions will do this instead of executing the sproc themselves.
}
sproc.cfc:
component {
function exec(procedure) {
local.result = {};
if (server.ColdFusion.productname == 'Railo') {
return new Railo().exec(arguments.procedure); // Has to be outside of sproc.cfc because ColdFusion throws a syntax error otherwise.
}
local.svc = new storedProc();
local.svc.setProcedure(arguments.procedure);
local.svc.addProcResult(name='qry');
try {
local.obj = local.svc.execute();
local.result.Prefix = local.obj.getPrefix();
local.result.qry = local.obj.getProcResultSets().qry;
} catch(any Exception) {
request.msg = Exception.Detail;
}
return local.result;
}
Railo.cfc:
component {
function exec(procedure) {
local.result = {};
try {
storedproc procedure=arguments.procedure result="local.result.Prefix" returncode="yes" {
procresult name="local.result.qry";
}
} catch(any Exception) {
request.msg = Exception.Message;
}
return local.result;
}
}
So I've been working on this all day, but tell me, is this a sane way to keep the source code the same if it's to be run on either a ColdFusion server or a Railo server?
Um... just use <cfstoredproc> instead of trying to use two different CFScript approaches that are mutually exclusive to each other of the CFML platforms.

Entity Framework 5 - read a record then delete it in loop

I am having issues with my application. I have a db table for a print queue. When I read from that table in a loop, once I add that record to the view model, I then want to delete it from the database...this would be the most efficient way to do it, but EF barks:
An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
I've tried using multiple contexts... but that didn't seem to work either. I've seen articles like Rick Strahl's, but frankly it was above my level of understanding, and not exactly sure if it helps my issue here and seemed quite an in depth solution for something as simple as this.
Is there a simple way to accomplish what I am trying to achieve here?
Here is my code:
public List<InventoryContainerLabelViewModel> CreateLabelsViewModel(int intFacilityId)
{
var printqRep = new Repository<InventoryContainerPrintQueue>(new InventoryMgmtContext());
var printqRepDelete = new Repository<InventoryContainerPrintQueue>(new InventoryMgmtContext());
IQueryable<InventoryContainerPrintQueue> labels =
printqRep.SearchFor(x => x.FacilityId == intFacilityId);
List<InventoryContainerLabelViewModel> labelsViewModel = new List<InventoryContainerLabelViewModel>();
if (labels.Count() > 0)
{
//Get printq record
foreach (InventoryContainerPrintQueue label in labels)
{
IEnumerable<InventoryContainerDetail> icDtls =
label.InventoryContainerHeader.InventoryContainerDetails;
//Get print details
foreach (InventoryContainerDetail icDtl in icDtls)
{
labelsViewModel.Add(new InventoryContainerLabelViewModel()
{
...
populate view model here
}
);//Add label to view model
} //for each IC detail
//Delete the printq record
printqRepDelete.Delete(label); <======== Error Here
} //foreach label loop
}//label count > 0
return labelsViewModel.ToList();
}
In the end, I added a column to the printq table for status, then in the the loop updated it to processed, then called a separate method to delete it.
public List<InventoryContainerLabelViewModel> CreateLabelsViewModel(int intFacilityId)
{
InventoryMgmtContext dbContext = new InventoryMgmtContext();
var printqRep = new Repository<InventoryContainerPrintQueue>(dbContext);
IEnumerable<InventoryContainerPrintQueue> unprintedPrtqRecs =
printqRep.SearchFor(x => x.FacilityId == intFacilityId && x.Printed == false);
List<InventoryContainerLabelViewModel> labelsViewModel = new List<InventoryContainerLabelViewModel>();
if (unprintedPrtqRecs.Count() > 0)
{
//Get printq record
foreach (InventoryContainerPrintQueue unprintedPrtqRec in unprintedPrtqRecs)
{
IEnumerable<InventoryContainerDetail> icDtls =
unprintedPrtqRec.InventoryContainerHeader.InventoryContainerDetails;
//Get container details to print
foreach (InventoryContainerDetail icDtl in icDtls)
{
labelsViewModel.Add(new InventoryContainerLabelViewModel()
{
...
}
);//Get IC details and create view model
} //for each IC detail
unprintedPrtqRec.Printed = true;
printqRep.Update(unprintedPrtqRec, unprintedPrtqRec, false);
} //foreach label loop
//Commit updated to Printed status to db
dbContext.SaveChanges();
}//label count > 0
return labelsViewModel;
}
public ActionConfirmation<int> DeletePrintQRecs(int intFacilityId)
{
InventoryMgmtContext dbContext = new InventoryMgmtContext();
var printqRep = new Repository<InventoryContainerPrintQueue>(dbContext);
IEnumerable<InventoryContainerPrintQueue> printedPrtqRecs =
printqRep.SearchFor(x => x.FacilityId == intFacilityId && x.Printed == true);
foreach (InventoryContainerPrintQueue printedPrtqRec in printedPrtqRecs)
{
//Delete the printq record
printqRep.Delete(printedPrtqRec, false);
}
//Save Changes on all deletes
ActionConfirmation<int> result;
try
{
dbContext.SaveChanges();
result = ActionConfirmation<int>.CreateSuccessConfirmation(
"All Label Print Q records deleted successfully.",
1);
}
catch (Exception ex)
{
result = ActionConfirmation<int>.CreateFailureConfirmation(
string.Format("An error occured attempting to {0}. The error was: {2}.",
"delete Label Print Q records",
ex.Message),
1
);
}
return result;
}

Entity Framework Newbie - Save to DB

I have 3 joined tables; ValidationRun has many Result which has many Error
The following code succeeds in saving to the Result and Error tables but not the ValidationRun.
Can you see the problem please?
private void WriteResultsToDB(SqlDataReader dr, XMLValidator validator)
{
using (var context = new ValidationResultsEntities())
{
var run = new ValidationRun { DateTime = DateTime.Now, XSDPath = this.txtXsd.Text };
//loop through table containing the processed XML
while (dr.Read())
{
var result = new Result
{
AddedDateTime = (DateTime)dr["Added"],
CustomerAcc = (string)dr["CustomerAcc"],
CustomerRef = (string)dr["CustomerRef"]
};
if (this.rdoRequest.Checked)
{
result.XMLMsg = (string)dr["RequestMSG"];
}
else
{
result.XMLMsg = (string)dr["ReplyMSG"];
}
if (validator.Validate(result.XMLMsg))
{
foreach (string error in validator.Errors)
{
result.Errors.Add(new Error { ErrorDescription = error });
}
}
else
{
//validator caught an error
result.Errors.Add(new Error { ErrorDescription = "XML could not be parsed" });
}
if (result.Errors.Count == 0) result.ValidFile = true; else result.ValidFile = false;
context.AddToResults(result);
context.SaveChanges();
}
}
You don't appear to be adding the run to any part of the context. If it were referenced by the result you are adding, perhaps, the change tracker would know it was supposed to be saved, but as it is written it is just some orphaned object that doesn't get attached anywhere.

Resources