JPA build entity manager with a specific JDBC connection instance - jpa

I want to manage the database connection outside entity manager context so that I can use it for different entity managers. The question is how can I build the entity manager factory or entity manager with my own connection instead of providing it with properties in persistence.xml?

In either case the answer is that you cannot, in SE you can specify the db connection properties when creating the EntityManagerFactory, but the db connection is still maintained by the EntityManager and for good reason, if you controlled this you could commit and rollback behind the EntityManager's back. If you gave the same db connection to multiple EntityManager's this would be chaos indeed, I am not sure why on earth you want to do this.
The best I can suggest is that you look into the EntityManager.getDelegate() (JPA 1.0) or EntityManager.unwrap(java.lang.Class cls) (JPA 2.0) methods they may return the underlying provider (ie. Hibernate) object which you may be able to pry the database connection out of, but you certainly won't be able to replace it.
In short really bad idea.

Related

EF Core 2.2: use same DbContext instance get record from database multiple times, always the same result

I am facing an issue: we have an ASP.NET Core 2.2 Web API project with EF Core 2.2. We are using default IOC framework to create the DbContext with scope lifetime. And we have a socket pipeline connected to our ASP.NET Web API service.
I find that when we change the data in the web frontend, the socket pipeline will always get the old result (we are using .FirstOrDefault() to fetch the data, it should not be the problem with first-level cache).
So I infer that it might be because of that the scope lifetime for DbContext, so I changed it to transient lifetime. And it works! We get the modified record.
I have two questions:
Is that behavior of DbContext by design? Or maybe I have some tricky issue in my code.
How much performance will the transient lifetime DbContext cost? Since maybe I will make every DbContext transient
1) Is that behavior of DbContext by design?
Yes
For each item in the result set If this is a tracking query, EF checks
if the data represents an entity already in the change tracker for the
context instance If so, the existing entity is returned If not, a new
entity is created, change tracking is setup, and the new entity is
returned
How Queries Work
2) How much performance will the transient lifetime DbContext cost?
Very little. Especially in ASP.NET Core, which has DbContext Pooling
Since maybe I will make every DbContext transient
But you shouldn't do that. Using a request-scoped DbContext is very useful. For instance you can use the DbContext in various layers of your application without having to pass one around, and you can manage transactions more easily.

.NETCore PostgreSQL "A command is already in progress"

I am developing a WebAPI on .NETCore accessing data to a POSTGRESQL DB.
I have troubles with the non-MARS support of PostgreSQL. NPGSQL is unable to support multiple connections from the same instance (as described in EntityFramework DbContext lifecycle + Postgres: "An operation is already in progress."). For Asynchronous management, this is blocking.
Unfortunately, I cannot find any solution to this.
At the moment, I inject my DB context with:
services.AddEntityFrameworkNpgsql().AddDbContextPool<DBApiContext>(opt => opt.UseNpgsql('connectionString');
I use EntityFramework.
Just for people who got stuck in this - In my case, it was a simple code change in the end of the method to fix this:
reader.close();
reader is an object of NpgsqlDataReader.
For who may be interested in: my problem was all about service scope and dependency injection.
The requestor was not a transient service, so that for every requests, even parallel, it was trying to access the DB.
Postgresql doesn't support MARS, then the second requests were rejected.
You need to have transient service requesting the access, for every invokation to use a different DB handler.

Dependency Injection with Entity Framework - Connection Strings

Im currently creating a middle tier layer for editing rules for an application. The data access is handled using entity framework and a repository class. My manager has suggested to inject the connection string for the database down to the repository class and I'm confused as to his thinking behind this?
Is there any need for this and what benefits would it provide?
Thanks
Dependency injection gives you freedom of changing the string when for example unit testing. In your case, I believe you would be better of mocking the database instead, but if you have a test database that is to be used instead of a mock, that lets you change a connection string when instanciating the object.

Getting a JDBC connection from EclipseLink

using EclipseLink as JPA 2.0 provider, I can obtain a JDBC connection by simply calling
Connection con = entityManager.unwrap(Connection.class);
But I'm unsure what I'm responsible for. Do I have to close the connection after submitting my queries? Or are I'm not allowed to close the connection, because EclipseLink also uses this connection internally. Or does it not care, because EclipseLink observes my behaviour and closes the connection automatically if I don't do it?
If you are in the context of a JPA transaction the connection will be managed by the provider (EclipseLink). If you are outside of a transaction you are responsible for managing the connection yourself.
See the following link for additional information:
http://wiki.eclipse.org/EclipseLink/Examples/JPA/EMAPI#Getting_a_JDBC_Connection_from_an_EntityManager
But I'm unsure what I'm responsible for. Do I have to close the
connection after submitting my queries? Or are I'm not allowed to
close the connection, because EclipseLink also uses this connection
internally.
A good and valid question. It seems that the documentation is lacking the semantics of the unwrap() calls.
Regarding EclipseLink, according from what I got from the source:
EclipseLink gives you a reference to the currently active connection which it uses for the currently active client session transaction. If no transaction is active, a new will be created, associated with the session and returned from the unwrap() method.
As a result, IMHO, a commit/rollback of such a obtained Connection may lead to undefined behavior and/or exceptions. Same is true for executing DML which changed records have been previously cached by eclipselink internal caches or for which managed entities exist.
So when using this API, especially if the underlying transaction is dirty, be careful.
If you can refer to internal eclipselink classes, you can access eclipselink internal connection pool to get a Connection exclusively (have a look at org.eclipse.persistence.sessions.server.ServerSession.getConnectionPool(String) ).

How to persist the same JPA Entity at multiple databases (distributed system)?

(How) is it possible to persist a JPA Entity at the databases of multiple servers without copying everything to DTOs?
We have a distributed system. Some applications do have DBs for caching purposes. The JPA Provider throws an Exception in which it complains that it cannot persist a detached object.
But I would like to preserve the ID of the entity with just persisting it in this additional DB.
(JPA 1.2, EJB 3.0, Glassfish v2.1, Toplink Essentials)
Don't em.persist(obj), just em.merge(obj). Merge works with both attached and detached objects.
If you are starting with a detached object, I would merge the object with the respective EntityManagers. If you're trying to keep the identity key the same across the objects, I would pull the key from the first object merged, and use it in the future.
What you probably (I don't know) don't want to do is try and merge an object that is managed by one EM with another EM. You can test this to see if it works, I just don't know what will happen if you try.
So.
YourEntity unattachedEntity = ... // your original entity object.
YourEntity managedEntity = em1.merge(unattachedEntity);
// managedEntity now has the primary key assigned by the DB
unattacheEntity.setPrimaryKey(managedEntity.getPrimaryKey());
em2.merge(unattachedEntity);
em3.merge(unattachedEntity);
Something like that should work ok.