I'd like to find out my data source name in the code. Is there a way of doing that?
I am using eclipselink.
thanks
To be more specific, my aim is to get an jdbc connection object.
I know i can do that thru:
datasource = (DataSource) (new InitialContext()).lookup("my_data_source_name")
connection = dataSource.getConnection();
But I don't want to hard code the data source name in my code.
I also tried
java.sql.Connection connection = em.unwrap(java.sql.Connection.class);
and it always return null.
.unwrap() should be the way to go, as written in EclipseLink wiki.
I also used to get null when calling em.unwrap(java.sql.Connection.class); because it was not inside a transaction. When called like this:
em.getTransaction().begin();
java.sql.Connection conn = em.unwrap(java.sql.Connection.class);
// ...
em.getTransaction().commit();
everything works fine!
java.sql.Connection connection = em.unwrap(java.sql.Connection.class);
Should work, what version are you using? Ensure that a transaction is active.
To get the data source name you should be able to use,
((JNDIConnector)em.unwrap(JpaEntityManager.class).getSession().getLogin().getConnector()).getName();
Here's what I've found helpful:
private DataSource createDataSource() {
ClientDataSource dataSource = new ClientDataSource();
dataSource.setServerName("localhost");
dataSource.setPortNumber(1527);
dataSource.setDatabaseName("sample");
dataSource.setUser("app");
dataSource.setPassword("app");
return dataSource;
}
private EntityManagerFactory getEntityManagerFactory() {
if (emf == null) {
Map properties = new HashMap();
properties
.put(PersistenceUnitProperties.NON_JTA_DATASOURCE,createDataSource());
emf = Persistence.createEntityManagerFactory(PU_NAME, properties);
}
return emf;
}
Can you create your datasource in the code, rather than configure via persistence.xml?
Related
In my EF project if I execute the following
using (EntityConnection con = new EntityConnection("name=HCMConnection"))
it throws the exception
The specified named connection is either not found in the configuration,
not intended to be used with the EntityClient provider, or not valid.
The connection string is in the Web.Config and it looks like following
<add name="HCMConnection" connectionString="Data Source=DEV-PROG-01;
Initial Catalog=HCM;
user id=HCMUser;
password=*******;
MultipleActiveResultSets=True"
providerName="System.Data.SqlClient" />
I suspect it does no like the SqlClient provider, does not it?
Thanks.
I believe you should have (replace settings class with the correct one for your app type). There is no EntityConnection constructor that can take the connection string name as a param to work.
using (EntityConnection con = new EntityConnection(SettingsClass.HCMConnection))
However its probably a better idea to let the dbcontext manage the connection instead of doing it manually, this constructor can take just the connection name.
using (MyDbContext con = new MyDbContext ("HCMConnection"))
And even better in your context class
public MyDbContext()
: base("HCMConnection")
Paul
Not clear what is the SettingsClass in my case, but I decided to use the same context to use its connection:
public ActionResult Education(ModelHCMContainer model)
{...
and execute the following
using (DbCommand cmd = model.Database.Connection.CreateCommand())
{
model.Database.Connection.Open();
try
{
cmd.CommandText = String.Concat("select ed.*,", ...
"order by ed.DateStart DESC");
using (var _reader = cmd.ExecuteReader())
{
using (ModelHCMContainer context = new ModelHCMContainer())
{
var records = ((IObjectContextAdapter)context).ObjectContext.Translate<HCMApplication.Models.POCO.Profile.HCMEducationPOCO>(_reader);
items = records.ToList();
}
}
}
finally
{
model.Database.Connection.Close();
}
}
It seems like working fine.
Thanks.
I am updating an application. I have replaced most of the queries in the app with calls to ejbs but the code below calls a huge procedure and it would be almost impossible to re-write.
I would like to return an ejb to the result set R but I have not been able to figure this out....
java.sql.ResultSet R = Cmd.executeQuery("SELECT * FROM TableData");
String[] Names = {"id","Project","Resource","Week","Hours"};
out.print(getTableXML(R,Names));
R.close();
My ejb:
public List<Gridmaster> getDisplayGridList() {
return em.createQuery("FROM Gridmaster order by gridid", Gridmaster.class).getResultList();
Is this possible or do I need to create an old style db connection?
Thanks for any help.
After hours of struggling with MiniProfiler to make it profile the Database queries, I have no luck and I'm getting the error:
A null was returned after calling the 'get_ProviderFactory' method on
a store provider instance of type
'StackExchange.Profiling.Data.ProfiledDbConnection'. The store
provider might not be functioning correctly.
I got through many SO posts but nothing has worked so far, like this post which is about the same error but with different configuration and well there's not an answer. Now I know that ProfiledDbConnection is not overriding DbProviderFactory and it's parent class DbConnection returns null in it's implementation of DbProviderFactory so the error is expectable but it should work somehow. There is a MiniProfilerEF.Initialize() but it seams to be usable for CodeFirst only and I'm using DatabaseFirst approach.
I have installed MiniProfiler, MiniProfiler.EF, MiniProfilerMVC3 nuget packages. And here is my code:
string connectionString = ConfigurationManager.ConnectionStrings["SqlConnection"].ConnectionString;
var sqlConnection = new SqlConnection(connectionString);
var profiled = new ProfiledDbConnection(sqlConnection, MiniProfiler.Current);
var db = new DbContext(profiled, true);
db.Set<Customer>().ToList();
And I'm using asp.net mvc4, EF5, DatabseFirst, MiniProfiler 2.1.0.0, Sql Server
Any Idea?
So, coming from your comment on Setup of mvc-mini-profiler for EF-db- first, have you tried removing the Mini Profiler-specific wrapper?
var profiled = new ProfiledDbConnection(sqlConnection, MiniProfiler.Current);
var db = new DbContext(profiled, true);
db.Set<Customer>().ToList();
Instead, just adding
protected void Application_Start()
{
// any other code
MiniProfilerEF.Initialize();
}
and then doing standard db access?
using (var db = new WordsEntities()) {
var posts = db.Customer.Take(4);
// more code
}
I am attempting to use Entity Framework code based migrations with my web site. I currently have a solution with multiple projects in it. There is a Web API project which I want to initialize the database and another project called the DataLayer project. I have enabled migrations in the DataLayer project and created an initial migration that I am hoping will be used to create the database if it does not exist.
Here is the configuration I got when I enabled migrations
public sealed class Configuration : DbMigrationsConfiguration<Harris.ResidentPortal.DataLayer.ResidentPortalContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(Harris.ResidentPortal.DataLayer.ResidentPortalContext context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data. E.g.
//
// context.People.AddOrUpdate(
// p => p.FullName,
// new Person { FullName = "Andrew Peters" },
// new Person { FullName = "Brice Lambson" },
// new Person { FullName = "Rowan Miller" }
// );
//
}
}
The only change I made to this after it was created was to change it from internal to public so the WebAPI could see it and use it in it's databaseinitializer. Below is the code in the code in the Application_Start that I am using to try to initialize the database
Database.SetInitializer(new MigrateDatabaseToLatestVersion<ResidentPortalContext, Configuration>());
new ResidentPortalUnitOfWork().Context.Users.ToList();
If I run this whether or not a database exists I get the following error
Directory lookup for the file "C:\Users\Dave\Documents\Visual Studio 2012\Projects\ResidentPortal\Harris.ResidentPortal.WebApi\App_Data\Harris.ResidentPortal.DataLayer.ResidentPortalContext.mdf" failed with the operating system error 2(The system cannot find the file specified.).
CREATE DATABASE failed. Some file names listed could not be created. Check related errors.
It seems like it is looking in the totally wrong place for the database. It seems to have something to do with this particular way I am initializing the database because if I change the code to the following.
Database.SetInitializer(new DropCreateDatabaseAlways<ResidentPortalContext>());
new ResidentPortalUnitOfWork().Context.Users.ToList();
The database will get correctly created where it needs to go.
I am at a loss for what is causing it. Could it be that I need to add something else to the configuration class or does it have to do with the fact that all my migration information is in the DataLayer project but I am calling this from the WebAPI project?
I have figured out how to create a dynamic connection string for this process. You need to first add this line into your EntityFramework entry on Web or App.Config instead of the line that gets put there by default.
<defaultConnectionFactory type="<Namespace>.<ConnectionStringFacotry>, <Assembly>"/>
This tells the program you have your own factory that will return a DbConnection. Below is the code I used to make my own factory. Part of this is a hack to get by the fact that a bunch of programmers work on the same set of code but some of us use SQL Express while others use full blown SQL Server. But this will give you an example to go by for what you need.
public sealed class ResidentPortalConnectionStringFactory: IDbConnectionFactory
{
public DbConnection CreateConnection(string nameOrConnectionString)
{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(ConfigurationManager.ConnectionStrings["PortalDatabase"].ConnectionString);
//save off the original catalog
string originalCatalog = builder.InitialCatalog;
//we're going to connect to the master db in case the database doesn't exist yet
builder.InitialCatalog = "master";
string masterConnectionString = builder.ToString();
//attempt to connect to the master db on the source specified in the config file
using (SqlConnection conn = new SqlConnection(masterConnectionString))
{
try
{
conn.Open();
}
catch
{
//if we can't connect, then append on \SQLEXPRESS to the data source
builder.DataSource = builder.DataSource + "\\SQLEXPRESS";
}
finally
{
conn.Close();
}
}
//set the connection string back to the original database instead of the master db
builder.InitialCatalog = originalCatalog;
DbConnection temp = SqlClientFactory.Instance.CreateConnection();
temp.ConnectionString = builder.ToString();
return temp;
}
}
Once I did that I coudl run this code in my Global.asax with no issues
Database.SetInitializer(new MigrateDatabaseToLatestVersion<ResidentPortalContext, Configuration>());
using (ResidentPortalUnitOfWork temp = new ResidentPortalUnitOfWork())
{
temp.Context.Database.Initialize(true);
}
In standard EJB 3, when injecting entity manager, persistence unit (which refers to datasource) is hardcoded into annotation: (or alternatively xml file)
#PersistenceContext(unitName = "myunit")
private EntityManager entityManager;
Is there a way to use an entity manager but to select data source by name at runtime?
Using EclipseLink, You can set a DataSource configured in your app server.
import org.eclipse.persistence.config.PersistenceUnitProperties;
...
....
Map props = new HashMap();
props.put(PersistenceUnitProperties.JTA_DATASOURCE, "dataSource");
EntityManagerFactory emf = Persistence.createEntityManagerFactory("UNIT_NAME", props);
EntityManager em = emf.createEntityManager();
PU_NAME refers to the name used in the file persistence.xml
dataSource refers name used in the app server for the jdbc Resource as "jdbc/sample"
Configure required data-sources & persistent-units in persistence.xml.
<persistence-unit name="UNIT_NAME" transaction-type="JTA">
<provider>PERSISTENCE_PROVIDER</provider>
<jta-data-source>java:DATA_SOURCE_NAME</jta-data-source>
</persistence-unit>
-- other units
Now at runtime you can build entity-manager for the required persistence-unit. Create separate persistence-units for each data-source.
//---
EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnitName);
EntityManager em = emf.createEntityManager();
//---
Else you can also build factory by providing a map of properties like db-url, userName etc.
createEntityManagerFactory(persistenceUnitName,propertiesMap);
This will create and return an EntityManagerFactory for the named persistence unit using the given properties. Therefore you can change the properties at runtime accordingly.
It is possible! I've done it and it works under JBoss AS and WebSphere.
I use a custom persistence provider which extends org.hibernate.ejb.HibernatePersistence (you need to modify a private static final field to set your persistence provider name into org.hibernate.ejb3.Ejb3Configuration.IMPLEMENTATION_NAME: this is a kind of black magic but it works). Make sure your persistence.xml's persistence units have the custom provider set in the <provider> tag and your custom provider is registered in META-INF/services/javax.persistence.spi.PersistenceProvider.
My provider overrides the createContainerEntityManagerFactory(PersistenceUnitInfo,Map) method called the Java EE container as such (for JTA datasource but it would be easy to do it also for non JTA datasource):
#Override
public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map) {
// load the DataSource
String newDataSourceName = ...; // any name you want
DataSource ds = (DataSource)(new InitialContext().lookup(newDataSourceName));
// modify the datasource
try {
try {
// JBoss implementation (any maybe other Java EE vendors except IBM WebSphere)
Method m = info.getClass().getDeclaredMethod("setJtaDataSource", DataSource.class);
m.setAccessible(true);
m.invoke(info, ds);
} catch (NoSuchMethodException e) {
// method does not exist (WebSphere?) => try the WebSphere way
// set the datasource name
Method m = info.getClass().getDeclaredMethod("setJtaDataSource", String.class);
m.setAccessible(true);
m.invoke(info, newDataSourceName);
// do the lookup
Method m2 = info.getClass().getDeclaredMethod("lookupJtaDataSource", String.class);
m2.setAccessible(true);
m2.invoke(info);
}
} catch (Throwable e) {
throw new RuntimeException("could not change DataSource for "+info.getClass().getName());
}
// delegate the EMF creation
return new HibernatePersistence().createContainerEntityManaferFactory(info, map);
}
The createEntityManagerFactory(String,Map) also overriden but is much simpler:
#Override
public EntityManagerFactory createEntityManagerFactory(String persistenceUnitInfo, Map map) {
// change the datasource name
String newDataSourceName = ...; // any name you want
if (map==null) map = new HashMap();
map.put(HibernatePersistence.JTA_DATASOURCE, newDataSourceName);
// delegate the EMF creation
return new HibernatePersistence().createEntityManaferFactory(persistenceUnitInfo, map);
}
Note that I only wrote here the core code. In fact, my persistence provider has a lot of other functionalities:
check that the DataSource is up and running
set the transaction manager for JBoss or WebSphere
cache the EMF for lower memory usage
reconfigure the Hibernate query plan cache for smaller memory usage
register JMX bean (to allow more than one EAR to get the same persistence unit name)
I want to indicate that the usage of
Persistence.createEntityManagerFactory(persistenceUnitName)
recommended in the answer of Nayan is classified by the JPA Specification (JSR 317) as follows (footnote in "9.2 Bootstrapping in Java SE Environments"):
"Use of these Java SE bootstrapping APIs may be supported in Java EE containers; however, support for such use is not required."
So this isn't a standard solution for EJB. Anyway, I can confirm that this is working in EclipseLink.
Note: I'm not yet allowed to post this as a comment.