I am new to Scala and I am looking at a bit of Scala code which involves a Spring JDBC template and a RowMapper:
It is something like this:
val db = jdbcTemplate.queryForObject(QUERY, new RowMapper[SomeObject]() {
def mapRow(ResultSet rs, int rowNum) {
var s = new SomeObject()
s.setParam1 = rs.getDouble("columnName")
return s
}
})
db
I am writing this from memory so I have just used generic names.
I was wondering why db is written at the end. I can't think of what purpose it serves.
Also, If I had several JDBC templates and an object like s in the example where I wanted to populate it's data with output from the several JDBC templates. Is it possible to do this in one function? Is it possible to have a mapRow function which doesn't return anything so that I could maybe have an array of templates and loop through them?
Thanks
The db at the end means return db where return statement is skipped. This is a standard convention in Scala. Seems like your code is a body of the function which suppose to return db. The first statement simply assigns the result of the query to a db
RowMapper interface can be replaced with implicit conversion to a function of the following type (ResultSet, Int) => SomeObject, which means that it takes two parameters (ResultSet and Int) and returns the result of type SomeObject
Related
I am trying to see if there is a way to improve the way data is inserted and updated.
I am using ORACLE DB with JDBC.
The current way i'm doing is to update (e.g.)customer record by using a FOR loop after checking if toUpdate is true . An Example such as the sample code below, followed by calling an existing DAO update() to do so. But this would not allow for the UPSERT of multiple data together.
However, is there a better way to UPSERT multiple data together?
if (toUpdate) {
for (Customer customerRec : customerRecList)
customerRecDAO.update(customerRec);
}
Yes you can use batching:
public <T> int saveInBatch(List<T> records, String sql, Function<T, MapSqlParameterSource> paramFn){
try{
MapSqlParameterSource[] params = records.stream().map(paramFn).toArray(MapSqlParameterSource[]::new);
int rowCount = jdbcTemplate.batchUpdate(sql, params);
return Arrays.stream(rowCount).sum();
}
catch(Exception e){
//exception handling
}
}
paramFn is a lambda of function such that you can map records to their values. example could be
(record)->{
return new MapSqlParameterSource("username" ,username),Integer.class);//just example
}
why we use MapSqlParameterSource
You can call saveInBatch in such a way that you pass smaller batches or customized batches of records. Suppose you have a million records then you may want to update only 200-400 records at a time so you can do something like below:
private <T> int saveRecords(List<T> records, String sql, Function<T, MapSqlParameterSource> paramFn) throws Exception{
return Lists.partition(records, 300).stream().map(batch-> saveInBatch(batch, sql, paramFn)).mapToInt(Integer::intValue).sum();
}
Note: above is not well optimized or streams are not used to their best but this is a working code I tried ages back :).
New to Oracle here. My experience is building web apps which send queries to a database and get a "result set" back, for example in Java with Spring and JdbcTemplate.
For example, here's a code sample with a regular SQL query, using a RowMapper class to turn the rows of a result set into a Java list:
public List<Widget> findAllWidgets() {
return jdbcTemplate.query("SELECT * FROM widgets", new WidgetRowMapper());
}
Now I am tasked with writing a query that calls a PL/SQL stored procedure. This procedure has two input arguments (these I can handle) and two output arguments (let's call them error_code and error_message). I want to send a query to the database that will (a) run the procedure with my inputs and (b) return the two outputs. I would be equally happy to have the two outputs as a "row" or simply bind them to two Java variables.
Here's what I've tried, and it's not throwing an error but it's not getting the output values, either. The Java variables errorCode and errorMessage remain empty strings:
public Map<String,String> callMyProcedure() {
String errorCode="";
String errorMessage="";
jdbcTemplate.update("call myprocedure(?,?,?,?)","input1","input2",errorCode,errorMessage);
return Map.of("errorCode",errorCode,"errorMessage",errorMessage);
}
The question is: How can I capture the values of the PL/SQL procedure's "OUT" variables when calling the procedure from Java with JdbcTemplate?
EDIT: I accepted Alex's answer which doesn't use JdbcTemplate, because it seems to be the better way. My own answer does use JdbcTemplate but takes a lot more code, so if you're searching for something that specifically answers the question, that will do it.
You can use plain JDBC.
final String charlie;
final String zulu;
try (CallableStatement cs = connection.prepareCall("{call myprocedure(?,?,?,?,?,?,?,?)}")) {
cs.setString(1, "foo");
cs.setString(2, "bar");
cs.setString(3, "baz");
cs.setString(4, "whisky");
cs.setString(5, "tango");
cs.setString(6, "foxtrot");
cs.registerOutParameter(7, Types.VARCHAR);
cs.registerOutParameter(8, Types.VARCHAR);
cs.execute();
connection.commit(); // optional
charlie = cs.getString(7);
zulu = cs.getString(8);
}
When using JDBC, it is dangerous to use the getInt method and similar ones, since they convert the type to primitive and zero is replaced by 0. It is better to use a (Integer) cs.getObject(). Similarly, setInt does not support the reference type.
You can get the connection under jdbcTemplate and get output using get methods as getNString
try (Connection connection = DataSourceUtils.getConnection(jdbcTemplate.getDataSource());
CallableStatement statement = connection.prepareCall("{call myprocedure(?,?,?,?,?,?,?,?)}");
statement.execute();
statement.getNString(1); // using index or your parameter name
Retrieves the value of the designated NCHAR, NVARCHAR or LONGNVARCHAR parameter as a String in the Java programming language.
I found some guidance from an older question here, and came up with this monstrosity:
public Map<String,Object> callMyProcedure() {
return jdbcTemplate.call(new CallableStatementCreator() {
#Override
public CallableStatement createCallableStatement(Connection connection) throws SQLException {
CallableStatement cs = connection.prepareCall("{call myprocedure(?,?,?,?,?,?,?,?)}");
cs.setString(1,"foo");
cs.setString(2,"bar");
cs.setString(3,"baz");
cs.setString(4,"whisky");
cs.setString(5,"tango");
cs.setString(6,"foxtrot");
cs.registerOutParameter(7, Types.VARCHAR);
cs.registerOutParameter(8, Types.VARCHAR);
return cs;
}
},Arrays.asList(
new SqlParameter(Types.VARCHAR),
new SqlParameter(Types.VARCHAR),
new SqlParameter(Types.VARCHAR),
new SqlParameter(Types.VARCHAR),
new SqlParameter(Types.VARCHAR),
new SqlParameter(Types.VARCHAR),
new SqlOutParameter("errorCode",Types.VARCHAR),
new SqlOutParameter("errorMessage",Types.VARCHAR)
));
}
It does work, but I'm looking for an answer that can do the same thing more succinctly. Maybe Spring has added a new interface to JdbcTemplate in the years since that older answer?
I have ontology loaded in Jena model. In Jena code, after creation of model and load the ontology, I want multiple Sparql queries run against the ontology.
So in main() method, I will create the model and read the ontology, how can I then run multiple queries.
Will I have a separate method() for each sparql query?
Kindly guide me how can I modularize the code?
regards
you can simply make the methods accept a model as an argument and then pass the generated model. for example:
public static void execQ(String queryString, Model model) {
Query query = QueryFactory.create(queryString);
try (QueryExecution qexec = QueryExecutionFactory.create(query, model)) {
ResultSet results = qexec.execSelect();
for (; results.hasNext(); ) {
QuerySolution soln = results.nextSolution();
RDFNode x = soln.get("varName"); // Get a result variable by name.
Resource r = soln.getResource("VarR"); // Get a result variable - must be a resource
Literal l = soln.getLiteral("VarL"); // Get a result variable - must be a literal
}
}
}
i separated my application into a DAL, BL, UI.
I used entity framework code first throw repositories to access the sql database.
public class Person{
...
}
public class PersonRepository{
Create(...){...}
Update(...){...}
Delete(...){...}
GetById(...){...}
Query(...){...}
...
Now the thing is the BL i'm working on a method to get all the Persons who are leaving near an adress
public GetPersonsNear(string Address){
...
}
private bool AddressesAreClose(string address1, string address2)
{
...
}
the thing is linq does'nt let me use my method (in a query passed in the "Query" method of the repository)
...
PersonRepository personRepository = new PersonRepository();
var person = repository.Query(p => AddressAreClose(adress,p.Adress);
...
therefor i needed to get All the elements of the table in a list using a simple foreach loop to make the tests and keeping only the relevant ones
...
PersonRepository personRepository = new PersonRepository();
var persons = personRepository.GetAll;
foreach(person in persons)
{
if(AdressAreClose(adress,person.adress))
...
}
for now i populated the database with only a few elements to test it, but i'm not sure it would work very well with the far more greater number it will contain later specially with all the test i'm planing to add
isn't there a more clever way to do this ??? I'm open to anything
Well first of all, you should use generics in your repository, even if it's constrained to Person. This way you can build pipes/filters off your queries to clean up your LINQ queries and facilitate reuse.
Of course, without seeing the full signature/implementation of your Query method, it's hard to tell. But either way, you need to return IEnumerable<Person> or IQueryable<Person> to make the following work.
So, you could turn AddressesAreClose into a pipe/filter, like this:
public static bool WhereAddressesAreClose(this IQueryable<Person> source, string address)
{
return source.Where(/* your conditions */);
}
Then you can use it in your LINQ query:
var person = repository
.Query() // Should be IQueryable<Person>
.WhereAddressAreClose(adress);
.ToList();
Depending on the size of your data and whether or not your implementing caching, you should limit the results on the server (database), not post-query with a foreach loop.
If the performance isn't great, consider adding indexes, using compiled queries or moving to a stored procedure.
I have an entity that I'd like to compare with a subset and determine to select all except the subset.
So, my query looks like this:
Products.Except(ProductsToRemove(), new ProductComparer())
The ProductsToRemove() method returns a List<Product> after it performs a few tasks. So in it's simplest form it's the above.
The ProductComparer() class looks like this:
public class ProductComparer : IEqualityComparer<Product>
{
public bool Equals(Product a, Product b)
{
if (ReferenceEquals(a, b)) return true;
if (ReferenceEquals(a, null) || ReferenceEquals(b, null))
return false;
return a.Id == b.Id;
}
public int GetHashCode(Product product)
{
if (ReferenceEquals(product, null)) return 0;
var hashProductId = product.Id.GetHashCode();
return hashProductId;
}
}
However, I continually receive the following exception:
LINQ to Entities does not recognize
the method
'System.Linq.IQueryable1[UnitedOne.Data.Sql.Product]
Except[Product](System.Linq.IQueryable1[UnitedOne.Data.Sql.Product],
System.Collections.Generic.IEnumerable1[UnitedOne.Data.Sql.Product],
System.Collections.Generic.IEqualityComparer1[UnitedOne.Data.Sql.Product])'
method, and this method cannot be
translated into a store expression.
Linq to Entities isn't actually executing your query, it is interpreting your code, converting it to TSQL, then executing that on the server.
Under the covers, it is coded with the knowledge of how operators and common functions operate and how those relate to TSQL. The problem is that the developers of L2E have no idea how exactly you are implementing IEqualityComparer. Therefore they cannot figure out that when you say Class A == Class B you mean (for example) "Where Person.FirstName == FirstName AND Person.LastName == LastName".
So, when the L2E interpreter hits a method it doesn't recognize, it throws this exception.
There are two ways you can work around this. First, develop a Where() that satisfies your equality requirements but that doesn't rely on any custom method. In other words, test for equality of properties of the instance rather than an Equals method defined on the class.
Second, you can trigger the execution of the query and then do your comparisons in memory. For instance:
var notThisItem = new Item{Id = "HurrDurr"};
var items = Db.Items.ToArray(); // Sql query executed here
var except = items.Except(notThisItem); // performed in memory
Obviously this will bring much more data across the wire and be more memory intensive. The first option is usually the best.
You're trying to convert the Except call with your custom IEqualityComparer into Entity SQL.
Obviously, your class cannot be converted into SQL.
You need to write Products.AsEnumerable().Except(ProductsToRemove(), new ProductComparer()) to force it to execute on the client. Note that this will download all of the products from the server.
By the way, your ProductComparer class should be a singleton, like this:
public class ProductComparer : IEqualityComparer<Product> {
private ProductComparer() { }
public static ProductComparer Instance = new ProductComparer();
...
}
The IEqualityComparer<T> can only be executed locally, it can't be translated to a SQL command, hence the error