How can Jdbc template be used for UPDATE query with IN clause? - sql

I've gone through various forums to handle the IN clause using spring's namedParamJdbcTemplate but i still do not get the stuff I'm exactly looking for.
Below is my issue:
I've the following method:
public void updateBatchTableForStatus(List<Integer> reportShellIds, String scheduleType) {
Map<String,List<Integer>> shellIds = Collections.singletonMap("reportShellIds", reportShellIds);
MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("reportShellIds", shellIds, Types.NUMERIC)
parameters.addValue("eventType", scheduleType, Types.VARCHAR);
this.namedParamJdbcTemplate.update(GET_EVENT_METADATA_INFO, parameters);
}
The query refered in above method is as defined below:
public static final String SQL_UPDATE_BATCH_LOOKUP_TABLE_FOR_STATUS_BY_BATCH_IDS = "" +
"UPDATE " +
TABLE_BATCH_REF + " BLK " +
"SET " +
"BLK.EXECUTION_STATUS_CODE = :eventType " +
"WHERE " +
"BLK.BATCH_ID in(:reportShellIds) ";
Datatype for BATCH_ID column is Number(24,0) and for the EXECUTION_STATUS_CODE column Varchar.
I'm using Oracle db.
However, the above method throws a SQL exception.
Can someone pls tell me where I'm wrong and what is the fix for it ?
Many thanks in advance.
Best Regards
LB

You are binding reportShellIds to a Map, but it needs to be a List for Spring to bind it correctly. Perhaps you meant shellIds.values() or the variable reportShellIds?

You can use another method with simple Map<String,Object> and place the array as is into the parameter map
public int update(String sql, java.util.Map<java.lang.String,?> paramMap)

Related

Unable to locate appropriate constructor on class [ClassName]

I want to send a sql query by using Spring JPA like :
"SELECT NEW com.blalba.model.service.FamilyMaterialDto "
+ "(ms.id, mi.partNumber, ftc.commodityType, ftc.materialType, ms.grade, ms.thickness, ms.width) "
+ "FROM MaterialInstance mi, FamilyTypeCommodity ftc, MaterialSpecification ms "
+ "WHERE ftc.materialFamily.id = :familyId "
+ "AND (:typeId is null OR ftc.materialType.id = :typeId) "
+ "AND ftc.id = ms.familyTypeCommodity.id "
+ "AND ms.id = mi.materialSpecification.id "
+ "AND mi.materialSpecification.isActive = true"
However, when I remove some fields like "ms.width", I get the error:
Unable to locate appropriate constructor on class [com.commencis.sova.model.service.FamilyMaterialDto]. Expected arguments are: java.lang.String, java.lang.String, com.commencis.sova.model.entity.material.CommodityType, com.commencis.sova.model.entity.material.MaterialType, com.commencis.sova.model.entity.material.Grade, com.commencis.sova.model.entity.material.Thickness [SELECT NEW com.commencis.sova.model.service.FamilyMaterialDto (ms.id, mi.partNumber, ftc.commodityType, ftc.materialType, ms.grade, ms.thickness) FROM com.commencis.sova.model.entity.material.MaterialSpecification ms, com.commencis.sova.model.entity.material.MaterialInstance mi, com.commencis.sova.model.entity.material.FamilyTypeCommodity ftc WHERE ftc.materialFamily.id = :familyId AND (:typeId is null OR ftc.materialType.id = :typeId) AND mi.materialSpecification.isActive = true AND ms.id = mi.materialSpecification.id AND ftc.id = ms.familyTypeCommodity.id]
I understand that return Object[] cannot be parsed to DTO object. If I write constructor without the parameter - "Width", it will work properly. However, I want to provide that a query can be sendable without some parameters(sometimes one of them, sometimes five of them) and a result can be parsable with FamilyMaterialDTO.
How can I do? I don't have to use DTO, if there is another solution for this problem, please recommend.
I think you can make the query to return a map and you can create a constructor for FamilyMaterialDTO which takes the argument as a map. And based on the keys present in the map you can set the values...
For simplicity let me create my own class.
Class foo { String a; Integer b; Boolean c;}
And a sample query
"select new map (a as a, b as b) from Foo f"
Now this query will return a list of maps and the size of the list depends on how many rows the query returns.
Now you can create a constructor like this. Assume the size of list is 1.
foo (List<Map<?,?> list) {
Map map = list.get(0);
If(map.containsKey("a")) this.a = map.get("a");
If(map.containsKey("b")) this.b = map.get("b");
If(map.containsKey("c")) this.c = map.get("c"); }

dart - mirror - how to know variable name using mirrors

I am editing my question to fully describe what i need exactly is. I want to create sql query using reflection based on the model/fields as follows.
here method getFieldName() is a dummy sample of my need because i don't know how to implement.
import 'package:reflection_test2/common/reflect/Reflector.dart';
#reflector
class Table
{
int id;
String name;
String sql = "SELECT " + getFieldName(name) + " FROM TABLE "
"WHERE " + getFieldName(id) + "=" + 1.toString();
String getFieldName(dynamic field)
{
String fieldName = sameWayToGetFieldName(field);
return fieldName;
}
}
You tagged your question with flutter. Flutter does not allow using dart:mirror package. So there is no way to retrieve the variable name.
PS. Why do you need the name of the variable? If you need named numbers, you can use Map class.
You should wrap the variable in a class then use reflection...Like this
class MyClass{
int myint = 9;
}
void getVariableNames(){
ClassMirror classMirror = reflectClass(MyClass);
for(var attribute in classMirror.declarations.values){
if(attribute is VariableMirror){
var attributeName = MirrorSystem.getName(attribute.simpleName);
print(attributeName);
}
}
}
main() {
getVariableNames();
}
PLEASE NOTE: Flutter doesn't support reflection/mirrors yet but you can try this out in dart.
https://flutter.dev/docs/resources/faq#does-flutter-come-with-a-reflectionmirrors-system

DBArrayList to List<Map> Conversion after Query

Currently, I have a SQL query that returns information to me in a DBArrayList.
It returns data in this format : [{id=2kjhjlkerjlkdsf324523}]
For the next step, I need it to be in a List<Map> format without the id: [2kjhjlkerjlkdsf324523]
The Datatypes being used are DBArrayList, and List.
If it helps any, the next step is a function to collect the list and then to replace all single quotes if any [SQL-Injection prevention]. Using:
listMap = listMap.collect() { "'" + Util.removeSingleQuotes(it) + "'" }
public static String removeSingleQuotes(s) {
return s ? s.replaceAll(/'"/, '') : s
}
I spent this morning working on it, and I found out that I needed to actually collect the DBArrayList like this:
listMap = dbArrayList.collect { it.getAt('id')}
If you're in a bind like I was and restrained to a specific schema this might help, but #ou_ryperd has the correct answer!
While using a DBArrayList is not wrong, Groovy's idiom is to use the db result as a collection. I would suggest you use it that way directly from the db:
Map myMap = [:]
dbhandle.eachRow("select fieldSomeID, fieldSomeVal from yourTable;") { row ->
map[row.fieldSomeID] = row.fieldSomeVal.replaceAll(/'"/, '')
}

PetaPoco db.SingleOrDefault<T> passing in where name as well as value

I am trying to write a generic method to call DB records.
All works except to make the method useful I need to passing the WHERE name value too...as well as the value to match.
Something like this...
T values = db.SingleOrDefault<T>("WHERE " + name + " = #0", value);
This works but its a bit of a clunk!
string sql = "WHERE " + name + " = #0";
T values = db.SingleOrDefault<T>(sql, value);
Can this be done with different syntax?
Thanks
You can create an extension method to hide the syntax if that bothers you
public static T SingleOrDefaultWithWhere<T>(this PetaPoco.Database db, string name, object value) {
string sql = "WHERE " + name + " = #0";
return db.SingleOrDefault<T>(sql, value);
}
And then just call
T values = db.SingleOrDefaultWithWhere<T>(name, value);

Is it possible to run native sql with entity framework?

I am trying to search an XML field within a table, This is not supported with EF.
Without using pure Ado.net is possible to have native SQL support with EF?
For .NET Framework version 4 and above: use ObjectContext.ExecuteStoreCommand() if your query returns no results, and use ObjectContext.ExecuteStoreQuery if your query returns results.
For previous .NET Framework versions, here's a sample illustrating what to do. Replace ExecuteNonQuery() as needed if your query returns results.
static void ExecuteSql(ObjectContext c, string sql)
{
var entityConnection = (System.Data.EntityClient.EntityConnection)c.Connection;
DbConnection conn = entityConnection.StoreConnection;
ConnectionState initialState = conn.State;
try
{
if (initialState != ConnectionState.Open)
conn.Open(); // open connection if not already open
using (DbCommand cmd = conn.CreateCommand())
{
cmd.CommandText = sql;
cmd.ExecuteNonQuery();
}
}
finally
{
if (initialState != ConnectionState.Open)
conn.Close(); // only close connection if not initially open
}
}
Using Entity Framework 5.0 you can use ExecuteSqlCommand to execute multi-line/multi-command pure SQL statements. This way you won't need to provide any backing object to store the returned value since the method returns an int (the result returned by the database after executing the command).
Sample:
context.Database.ExecuteSqlCommand(#
"-- Script Date: 10/1/2012 3:34 PM - Generated by ExportSqlCe version 3.5.2.18
SET IDENTITY_INSERT [Students] ON;
INSERT INTO [Students] ([StudentId],[FirstName],[LastName],[BirthDate],[Address],[Neighborhood],[City],[State],[Phone],[MobilePhone],[Email],[Enrollment],[Gender],[Status]) VALUES (12,N'First Name',N'SecondName',{ts '1988-03-02 00:00:00.000'},N'RUA 19 A, 60',N'MORADA DO VALE',N'BARRA DO PIRAÍ',N'Rio de Janeiro',N'3346-7125',NULL,NULL,{ts '2011-06-04 21:25:26.000'},2,1);
INSERT INTO [Students] ([StudentId],[FirstName],[LastName],[BirthDate],[Address],[Neighborhood],[City],[State],[Phone],[MobilePhone],[Email],[Enrollment],[Gender],[Status]) VALUES (13,N'FirstName',N'LastName',{ts '1976-04-12 00:00:00.000'},N'RUA 201, 2231',N'RECANTO FELIZ',N'BARRA DO PIRAÍ',N'Rio de Janeiro',N'3341-6892',NULL,NULL,{ts '2011-06-04 21:38:38.000'},2,1);
");
For more on this, take a look here: Entity Framework Code First: Executing SQL files on database creation
For Entity Framework 5 use context.Database.SqlQuery.
And for Entity Framework 4 use context.ExecuteStoreQuery
the following code:
public string BuyerSequenceNumberMax(int buyerId)
{
string sequenceMaxQuery = "SELECT TOP(1) btitosal.BuyerSequenceNumber FROM BuyerTakenItemToSale btitosal " +
"WHERE btitosal.BuyerID = " + buyerId +
"ORDER BY CONVERT(INT,SUBSTRING(btitosal.BuyerSequenceNumber,7, LEN(btitosal.BuyerSequenceNumber))) DESC";
var sequenceQueryResult = context.Database.SqlQuery<string>(sequenceMaxQuery).FirstOrDefault();
string buyerSequenceNumber = string.Empty;
if (sequenceQueryResult != null)
{
buyerSequenceNumber = sequenceQueryResult.ToString();
}
return buyerSequenceNumber;
}
To return a List use the following code:
public List<PanelSerialList> PanelSerialByLocationAndStock(string locationCode, byte storeLocation, string itemCategory, string itemCapacity, byte agreementType, string packageCode)
{
string panelSerialByLocationAndStockQuery = "SELECT isws.ItemSerialNo, im.ItemModel " +
"FROM Inv_ItemMaster im " +
"INNER JOIN " +
"Inv_ItemStockWithSerialNoByLocation isws " +
" ON im.ItemCode = isws.ItemCode " +
" WHERE isws.LocationCode = '" + locationCode + "' AND " +
" isws.StoreLocation = " + storeLocation + " AND " +
" isws.IsAvailableInStore = 1 AND " +
" im.ItemCapacity = '" + itemCapacity + "' AND " +
" isws.ItemSerialNo NOT IN ( " +
" Select sp.PanelSerialNo From Special_SpecialPackagePriceForResale sp " +
" Where sp.PackageCode = '" + packageCode + "' )";
return context.Database.SqlQuery<PanelSerialList>(panelSerialByLocationAndStockQuery).ToList();
}
Keep it simple
using (var context = new MyDBEntities())
{
var m = context.ExecuteStoreQuery<MyDataObject>("Select * from Person", string.Empty);
//Do anything you wonna do with
MessageBox.Show(m.Count().ToString());
}
public class RaptorRepository<T>
where T : class
{
public RaptorRepository()
: this(new RaptorCoreEntities())
{
}
public RaptorRepository(ObjectContext repositoryContext)
{
_repositoryContext = repositoryContext ?? new RaptorCoreEntities();
_objectSet = repositoryContext.CreateObjectSet<T>();
}
private ObjectContext _repositoryContext;
private ObjectSet<T> _objectSet;
public ObjectSet<T> ObjectSet
{
get
{
return _objectSet;
}
}
public void DeleteAll()
{
_repositoryContext
.ExecuteStoreCommand("DELETE " + _objectSet.EntitySet.ElementType.Name);
}
}
So what do we say about all this in 2017? 80k consultations suggests that running a SQL request in EF is something a lot of folk want to do. But why? For what benefit?
Justin, a guru with 20 times my reputation, in the accepted answer gives us a static method that looks line for line like the equivalent ADO code. Be sure to copy it well because there are a few subtleties to not get wrong. And you're obliged to concatenate your query with your runtime parameters since there's no provision for proper parameters. So all users of this method will be constructing their SQL with string methods (fragile, untestable, sql injection), and none of them will be unit testing.
The other answers have the same faults, only moreso. SQL buried in double quotes. SQL injection opportunities liberally scattered around. Esteemed peers, this is absolutely savage behaviour. If this was C# being generated, there would be a flame war. We don't even accept generating HTML this way, but somehow its OK for SQL. I know that query parameters were not the subject of the question, but we copy and reuse what we see, and the answers here are both models and testaments to what folk are doing.
Has EF melted our brains? EF doesn't want you to use SQL, so why use EF to do SQL.
Wanting to use SQL to talk to a relational DB is a healthy, normal impulse in adults. QueryFirst shows how this could be done intelligently, your sql in .sql file, validated as you type, with intellisense for tables and columns. The C# wrapper is generated by the tool, so your queries become discoverable in code, with intellisense for your inputs and results. End to end strong typing, without ever having to worry about a type. No need to ever remember a column name, or its index. And there are numerous other benefits... The temptation to concatenate is removed. The possibility of mishandling your connections also. All your queries and the code that accesses them are continuously integration-tested against your dev DB. Schema changes in your DB pop up as compile errors in your app. We even generate a self test method in the wrapper, so you can test new versions of your app against existing production databases, rather than waiting for the phone to ring. Anyone still need convincing?
Disclaimer: I wrote QueryFirst :-)