Neo4j Mapping Exception - neo4j

I am a getting a MappingException error when executing the following piece of code:
Configuration configuration = new Configuration.Builder()
.uri("file:///var/lib/neo4j/data/databases/graph.db")
.credentials("neo4j","noor")
.build();
SessionFactory sessionFactory = new SessionFactory(configuration,"OntologyDescription","info.testNeo");
Session session = sessionFactory.openSession();
ResourceDescription classDescription = OntologyUtils.getClassDescription(classIRI,
dogont);
session.save(classDescription);
sessionFactory.close();
Full trace:
Exception in thread "main" org.neo4j.ogm.exception.core.MappingException: Field with primary id is null for entity state
at org.neo4j.ogm.context.MappingContext.nativeId(MappingContext.java:514)
at org.neo4j.ogm.context.EntityGraphMapper.newNodeBuilder(EntityGraphMapper.java:318)
at org.neo4j.ogm.context.EntityGraphMapper.mapEntity(EntityGraphMapper.java:257)
at org.neo4j.ogm.context.EntityGraphMapper.mapRelatedEntity(EntityGraphMapper.java:797)
at org.neo4j.ogm.context.EntityGraphMapper.link(EntityGraphMapper.java:501)
at org.neo4j.ogm.context.EntityGraphMapper.mapEntityReferences(EntityGraphMapper.java:414)
at org.neo4j.ogm.context.EntityGraphMapper.mapEntity(EntityGraphMapper.java:265)
at org.neo4j.ogm.context.EntityGraphMapper.map(EntityGraphMapper.java:149)
at org.neo4j.ogm.session.delegates.SaveDelegate.lambda$save$1(SaveDelegate.java:89)
at java.util.Collections$SingletonList.forEach(Collections.java:4822)
at org.neo4j.ogm.session.delegates.SaveDelegate.save(SaveDelegate.java:89)
at org.neo4j.ogm.session.delegates.SaveDelegate.save(SaveDelegate.java:51)
at org.neo4j.ogm.session.Neo4jSession.save(Neo4jSession.java:468)
at Examples.TestNeo4j.main(TestNeo4j.java:41)
I am getting the error only when getting classDescription from the OntologyUtils.getClassDescription method. However, if I instantiate a ResourceDescription newly, I don't get the error. In short, OntologyUtils.getClassDescription calls several other methods to add information to the new instance.

This problem was because the package names contain capital letters. As mentioned in this GitHub issue, package names should be completely in lower case

Related

"Guid should contain 32 digits" serilog error with sql server sink

I am getting this error occasionally with the MSSQLServer sink. I can't see what's wrong with this guid. Any ideas? I've verified in every place I can find the data type of the source guid is "Guid" not a string. I'm just a bit mystified.
Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).Couldn't store <"7526f485-ec2d-4ec8-bd73-12a7d1c49a5d"> in UserId Column. Expected type is Guid.
The guid in this example is:
7526f485-ec2d-4ec8-bd73-12a7d1c49a5d
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
seems to match the template to me?
Further details:
This is an occasional issue, but when it arises it arises a lot. It seems to be tied to specific Guids. Most Guids are fine, but a small subset have this issue. Our app logs thousands of messages a day, but these messages are not logged (because of the issue) so it is difficult for me to track down exactly where the specific logs that are causing this error come from. However, we use a centralized logging method that is run something like this. This test passes for me, but it mirrors the setup and code we use for logging generally, which normally succeeds. As I said, this is an intermittent issue:
[Fact]
public void Foobar()
{
// arrange
var columnOptions = new ColumnOptions
{
AdditionalColumns = new Collection<SqlColumn>
{
new SqlColumn {DataType = SqlDbType.UniqueIdentifier, ColumnName = "UserId"},
},
};
columnOptions.Store.Remove(StandardColumn.MessageTemplate);
columnOptions.Store.Remove(StandardColumn.Properties);
columnOptions.Store.Remove(StandardColumn.LogEvent);
columnOptions.Properties.ExcludeAdditionalProperties = true;
var badGuid = new Guid("7526f485-ec2d-4ec8-bd73-12a7d1c49a5d");
var connectionString = "Server=(localdb)\\MSSQLLocalDB;Database=SomeDb;Trusted_Connection=True;MultipleActiveResultSets=true";
var logConfiguration = new LoggerConfiguration()
.MinimumLevel.Information()
.Enrich.FromLogContext()
.WriteTo.MSSqlServer(connectionString, "Logs",
restrictedToMinimumLevel: LogEventLevel.Information, autoCreateSqlTable: false,
columnOptions: columnOptions)
.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Information);
Log.Logger = logConfiguration.CreateLogger();
// Suspect the issue is with this line
LogContext.PushProperty("UserId", badGuid);
// Best practice would be to do something like this:
// using (LogContext.PushProperty("UserId", badGuid)
// {
Log.Logger.Information(new FormatException("Foobar"),"This is a test");
// }
Log.CloseAndFlush();
}
One thing I have noticed since constructing this test code is that the "PushProperty" for the UserId property is not captured and disposed. Since behaviour is "undefined" in this case, I am inclined to fix it anyway and see if the problem goes away.
full stack:
2020-04-20T08:38:17.5145399Z Exception while emitting periodic batch from Serilog.Sinks.MSSqlServer.MSSqlServerSink: System.ArgumentException: Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).Couldn't store <"7526f485-ec2d-4ec8-bd73-12a7d1c49a5d"> in UserId Column. Expected type is Guid.
---> System.FormatException: Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
at System.Guid.GuidResult.SetFailure(Boolean overflow, String failureMessageID)
at System.Guid.TryParseExactD(ReadOnlySpan`1 guidString, GuidResult& result)
at System.Guid.TryParseGuid(ReadOnlySpan`1 guidString, GuidResult& result)
at System.Guid..ctor(String g)
at System.Data.Common.ObjectStorage.Set(Int32 recordNo, Object value)
at System.Data.DataColumn.set_Item(Int32 record, Object value)
--- End of inner exception stack trace ---
at System.Data.DataColumn.set_Item(Int32 record, Object value)
at System.Data.DataRow.set_Item(DataColumn column, Object value)
at Serilog.Sinks.MSSqlServer.MSSqlServerSink.FillDataTable(IEnumerable`1 events)
at Serilog.Sinks.MSSqlServer.MSSqlServerSink.EmitBatchAsync(IEnumerable`1 events)
at Serilog.Sinks.PeriodicBatching.PeriodicBatchingSink.OnTick()
RESOLUTION
This issue was caused because someone created a log message with a placeholder that had the same name as our custom data column, but was passing in a string version of a guid instead of one typed as a guid.
Very simple example:
var badGuid = "7526f485-ec2d-4ec8-bd73-12a7d1c49a5d";
var badGuidConverted = Guid.Parse(badGuid); // just proving the guid is actually valid.
var goodGuid = Guid.NewGuid();
using (LogContext.PushProperty("UserId",goodGuid))
{
Log.Logger.Information("This is a problem with my other user {userid} that will crash serilog. This message will never end up in the database.", badGuid);
}
The quick fix is to edit the message template to change the placeholder from {userid} to something else.
Since our code was centralized around the place where the PushProperty occurs, I put some checks in there to monitor for this and throw a more useful error message in the future when someone does this again.
I don't see anything obvious in the specific code above that would cause the issue. The fact that you call PushProperty before setting up Serilog would be something I would change (i.e. set up Serilog first, then call PushProperty) but that doesn't seem to be the root cause of the issue you're having.
My guess, is that you have some code paths that are logging the UserId as a string, instead of a Guid. Serilog is expecting a Guid value type, so if you give it a string representation of a Guid it won't work and will give you that type of exception.
Maybe somewhere in the codebase you're calling .ToString on the UserId before logging? Or perhaps using string interpolation e.g. Log.Information("User is {UserId}", $"{UserId}");?
For example:
var badGuid = "7526f485-ec2d- 4ec8-bd73-12a7d1c49a5d";
LogContext.PushProperty("UserId", badGuid);
Log.Information(new FormatException("Foobar"), "This is a test");
Or even just logging a message with the UserId property directly:
var badGuid = "7526f485-ec2d-4ec8-bd73-12a7d1c49a5d";
Log.Information("The {UserId} is doing work", badGuid);
Both snippets above would throw the same exception you're having, because they use string values rather than real Guid values.

How to get DB connection in grails 3

What is proper way to get DB connection in Grails 3?
For grails 2 following code has works:
((SessionImpl) sessionFactory.getCurrentSession()).connection() // sessionFactory initialized in bootstrap
But after migration to Grails 3 sometimes I see exceptions in the log:
java.sql.SQLException: Operation not allowed after ResultSet closed at
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:957) at
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:896) at
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:885) at
com.mysql.jdbc.SQLError.createSQLException(SQLError.java:860) at
com.mysql.jdbc.ResultSetImpl.checkClosed(ResultSetImpl.java:743) at
com.mysql.jdbc.ResultSetImpl.findColumn(ResultSetImpl.java:1037) at
com.mysql.jdbc.ResultSetImpl.getLong(ResultSetImpl.java:2757) at
com.mchange.v2.c3p0.impl.NewProxyResultSet.getLong(NewProxyResultSet.java:424)
at java_sql_ResultSet$getLong$3.call(Unknown Source)
It happens for 0,01% of requests
Grails 3.2.11
Gorm 6.0.12
I guess it depends on where you need it, but you can inject a DataSource into a service.
javax.sql.DataSource dataSource
Then you can just use
dataSource.getConnection()
Also be aware of the changes to flush mode in GORM 6 (http://gorm.grails.org/6.0.x/hibernate/manual/ section 1.2.1). If an upstream save/commit is failing, your result set could be incidentally closed and trigger an error that looks like this while not really have anything to do with this particular line of code at all. I'd (very temporarily) set back to the old flush mode and see if the problem goes away, before tracking much more down!
From grails docs, you can get the actual dataSource bean. From that you can access the connection or use it to query your db
import groovy.sql.Sql
def dataSource
println "connection: ${dataSource.connection}"
Sql sql = new Sql(dataSource)
sql.eachRow("SELECT * FROM note") { row ->
println "row: ${row}"
}
Use 'dataSourceUnproxied' to avoid Hibernate transaction and session issues:
def dataSourceUnproxied
For executing queries inside current hibernate transactions following construction can be used:
sessionFactory.currentSession.doWork {connection ->
new Sql(connection).execute(query, params)
}

Stale exception even using static lock method

I am not new to hibernate, concurrrency problems, and stale exceptions.
Im working in grails with GORM in a high concurrent environment. Optimistic locking is on and im using static lock method whithin a transactional service.
for(Entity entity : entityList) {
//refresh and lock for update
entity.refresh();
entity = Entity.lock(entity.id)
entity.setSomeData(new Date());
entity.save()
}
It is somehow possible to have an HibernateOptimisticLockingFailureException in this scenario??
Please note the stack trace:
Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.xxxxx.xxx.xxxxx.Entity#48225]
at org.hibernate.dialect.lock.PessimisticWriteSelectLockingStrategy.lock(PessimisticWriteSelectLockingStrategy.java:94)
at org.hibernate.persister.entity.AbstractEntityPersister.lock(AbstractEntityPersister.java:1954)
at org.hibernate.event.internal.AbstractLockUpgradeEventListener.upgradeLock(AbstractLockUpgradeEventListener.java:102)
at org.hibernate.event.internal.DefaultLoadEventListener.loadFromSessionCache(DefaultLoadEventListener.java:560)
at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:430)
at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:212)
at org.hibernate.event.internal.DefaultLoadEventListener.lockAndLoad(DefaultLoadEventListener.java:391)
at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:153)
at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1070)
at org.hibernate.internal.SessionImpl.access$2000(SessionImpl.java:176)
at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.load(SessionImpl.java:2544)
at org.hibernate.internal.SessionImpl.get(SessionImpl.java:1023)
at org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate$5.doInHibernate(GrailsHibernateTemplate.java:282)
at org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate.doExecute(GrailsHibernateTemplate.java:179)
at org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate.lock(GrailsHibernateTemplate.java:279)
at org.codehaus.groovy.grails.orm.hibernate.HibernateGormStaticApi.lock(HibernateGormStaticApi.groovy:221)
at com.xxxxx.xxx.xxxxx.Entity.lock(Entity.groovy)
How is possible for static Entity.lock() to throw a stale object exception??

Autofac error: The instance registration can support SingleInstance() sharing only

When I try to register my class with autofac I get the following error: "The instance registration 'GetAllDivisionsCommand' can support SingleInstance() sharing only".
I don't understand why I'm getting this error, but assume it's something to do with the class having static member variables used for caching as that's the only thing that's different about this class. I haven't had any trouble registering any other classes as either SingleInstance or InstancePerDependency.
Essentially, the class is used to retrieve a rarely changing list of divisions from the database, and caches the result. Each time the command is run, it first checks for changes on the database and then re-runs the query if changes are detected; if not, it returns the cached list.
So I am trying to register GetAllDivisionsCommand with Autofac as an IGetAllDivisionsCommand. IGetAllDivisionsCommand itself implements IInjectableCommand, which is just a marker interface, and ICachedListCommand. The concrete command class inherits from the abstract base class CachedListCommand which is where the static member variables live.
Does anyone know what would cause this error message? SingleInstance won't work for me as I can't keep reusing the same session.
Code:
Type commandType = typeof(IInjectedCommand);
Type aCommandType = typeof(GetAllDivisions);
var commands =
from t in aCommandType.Assembly.GetExportedTypes()
where t.Namespace == aCommandType.Namespace
&& t.IsClass
&& !t.IsAbstract
&& (commandType.IsAssignableFrom(t))
let iface = t.GetInterfaces().FirstOrDefault(x => "I" + t.Name == x.Name)
select new { Command = t, Interface = iface };
foreach (var cmd in commands)
{
builder.RegisterInstance(cmd.Command).As(cmd.Interface).InstancePerLifetimeScope();
}
RegisterInstace as the name implies is for registering instances not types.
What you need is RegisterType:
foreach (var cmd in commands)
{
builder.RegisterType(cmd.Command).As(cmd.Interface).InstancePerLifetimeScope();
}
And by the way with the Autofac scanning feature your registration code is roughly equivalent:
builder
.RegisterAssemblyTypes(aCommandType.Assembly)
.AssignableTo<IInjectedCommand>()
.InNamespace(aCommandType.Namespace)
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
In my case, I did want RegisterInstance because I actually have an instance in hand that I wanted to register.
I had
builder.RegisterInstance(myInstance).InstancePerDependency();
The documentation for InstancePerDependency reads:
Configure the component so that every dependent component or call to
Resolve() gets a new, unique instance (default.)
On closer inspection, it makes sense that registering an instance with "instance per dependency" is not possible, since it is not possible for Autofac to give back a new instance each time Resolve is called if there is in fact 1 instance registered.
So, in my case, the solution was this.
builder.RegisterInstance(myInstance).SingleInstance();
The Autofac exception could possibly have been worded more clearly to explain this problem.

Grails: Accessing GORM from a background thread

I have been struggling with this error for a week now, and I am seriously losing my mind over this! I have tried multible implementations and work-arounds and hacks and what not, but I just keep stubling into just another exception.
I am using the Executor plugin to run a method asynchroniously:
runAsync{
run(...)
}
The method initially deletes some objects:
page.delete(flush:true)
And then later possibly recreating those objects:
def page = new Page(type : Page.TYPE_TABLE, domain : domainVersion.domain, identifier : tableName)
page.save(flush: true, failOnError: true)
But that fails with the following exception:
Caused by: org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.ramboll.egs.ohs.domain.Domain#1]
The relationship between the Page and Domain is simply implemented by Page having a Domain attribute. No hasMany og belongsTo - as I was discouraged from this in an earlier post due to performance issues.
I think I have tried all thinkable combinations of save, merge, withTransachtion and PersistenceContextInterceptor...
How is this supposed to work? Examples please.
Thanks in advance!
It doesn't appear that working in a new thread is the issue, it looks like a standard validation problem. It's saying that the Page is null, which indicates a validation error since save() returns the instance if it was successful, or null if there's a one or more validation errors. There are a few options:
def page = new Page(type : Page.TYPE_TABLE,
domain: dbUpdate.domainVersion.domain, identifier: tableName)
page.save(flush:true)
if (page.hasErrors()) {
// handle errors
}
else {
def pageVersion = createPageVersion(page, dbUpdate.domainVersion,
con, tableName, dbUpdate.author).save(flush:true)
}
or use failOnError to throw an exception:
def page = new Page(type : Page.TYPE_TABLE, identifier: tableName,
domain: dbUpdate.domainVersion.domain).save(flush:true, failOnError: true)
def pageVersion = createPageVersion(page, dbUpdate.domainVersion,
con, tableName, dbUpdate.author).save(flush:true)

Resources