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"); }
Related
I have following User table and repository.
User:
id;name;job;age
1;steve;nurse;33
2;steve;programmer;null
3;steve;programmer;null
Repository method:
#Query("SELECT u FROM User u WHERE ("
+ "LOWER(u.name) = LOWER(:name) AND "
+ "LOWER(u.beruf) = LOWER(:job) AND "
+ "LOWER(u.alter) = LOWER(:age))")
public List<User> findUsers(#Param("name") String name,
#Param("job") String job,
#Param("age") String age);
If I call the repository method with following parameters
String name = "steve";
String job = "programmer";
List<User> result = repository.findUsers(name, job, null); // empy list ..why ?
I get an empty list as result, although I expect to get the entities with id=2 and id=3 as result.
What am I doing wrong ? How should I change the query to get the two entities as result.
Thanks
According to the documentation this behaviour is normal there is no way to ignore null fields. using #Query method.
instead you can use the query method specifications.
more information [here][jpa documentaiton]
if you want to keep your existing method you can also go like this:
#Query("SELECT u FROM User u WHERE ("
+ "LOWER(u.name) = LOWER(:name) AND "
+ "LOWER(u.beruf) = LOWER(:job) AND "
+ "( " +
" :age is null or LOWER(u.alter) = LOWER(:age) " +
")"
)
public List<User> findUsers(#Param("name") String name,
#Param("job") String job,
#Param("age") String age);
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);
I'm trying to write function for selecting optional columns in linq(columns that may not exist). The problem is in linq like this:
using (DataDataContext db = new DataDataContext()){
var collection = from t in table
select new
{
Nonoptional = t.A;
Optional = IsInDB("table","B") ? t.B : -1; //this is optional column
}}
Unfortunately, this won't work because the fragment near Optional will be translated to case statement and error arises that column not exists.
So i decided to "cover" it with function:
using (DataDataContext db = new DataDataContext()){
var collection = from t in table
select new
{
Nonoptional = t.A;
Optional = IsInDB("table","B") ? OptionalColumnValue<int>("table","B","id_table",t.id_table) : -1; //this is optional column
}}
I want this function to be universal. It should work like that" If there is no value or column is nullable and value is null then return default value for type.
I came up with something like this:
//table,column - obvious,id_column - PK column of table, id - id of currently processing record
public static T OptionalColumnValue<T>(string table,string column,string id_columm,int id) T t = default(T);
DataDataContext db = new DataDataContext();
IEnumerable<object> value = db.ExecuteQuery<object>("select " + column + " from " + table + " where " + id_columm + " = " + id.ToString());
List<object> valueList = value.ToList();
if (valueList.Count == 1)//here is the problem
t = (T)valueList.First();
return t;
}
When there is null value db.ExecuteQuery return something like object{}. I'm assuming this is "empty" object,with nothing really in there. I was thinking about checking for "emptiness" of this object( BTW this is not DBull).
When i realised that this is no way either with concrete value in this column(it cannot cast it to return correct type), then I tried db.ExecuteQuery<T>. Then concrete value - OK, null - Exception.
I thought, maybe Nullable<T> as return value. Nop, because string also can be T.
I don't know what to do next. Maybe there's another solution to this problem.
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)
I want to customize the update function of ORM. By default, ORM loads the object that needs to be updated, makes updates, and then saves the object. I want to update a record when a certain condition is satisfied.
For example :
I want to update payment mode from credit card to cash. Before updating records I want to check that I already have a cash payment mode. If one exists then I do not need to update a record otherwise update the record.
For the above checking I have used this SQL:
SELECT COUNT(*)
FROM hr_lookup_paymentmode
WHERE PaymentMode = 'cash'
AND modeid <> '10'
Equivalent HQL:
/**
* #hint Determines total number of results with same value of search for update purposes.
*/
remote numeric function searchUpdateCount(string q,numeric modeid ) output="false" {
var hqlString = "";
var whereClause = "";
var params = {};
hqlString = hqlString & "SELECT count(*) ";
hqlString = hqlString & "FROM hr_lookup_paymentmode";
if (len(arguments.q) gt 0)
{
whereClause = ListAppend(whereClause, " PaymentMode = '#arguments.q#'", "|");
whereClause = ListAppend(whereClause, "modeid <> '#arguments.modeid#'", "|");
whereClause = Replace(whereClause, "|", " AND ", "all");
}
if (len(whereClause) gt 0){
hqlString = hqlString & " WHERE " & whereClause;
}
return ormExecuteQuery(hqlString, false, params)[1];
}
Parameter q = 'cash' and modeid = 10. If count found is greater than 0 means record already exists, otherwise go for update.
Please help me apply this logic.
You can use ORM event handlers - either globally defined or defined in specific ORM objects. Here is some information on event handlers, but basically you would do the following in your ORM object:
function preUpdate( obj, data ){
{do stuff here }
}
In this example obj is the ORM entity you are trying to save and data is a structure containing the old data from the ORM entity. You would simply add your logic to the body of the function.