Spring integration jdbc array update query spel expression - spring-integration

I'm trying to create an 'update-query' for my JdbcPollingChannelAdapter given following workflow :
Select 500 records of type A from database
Update 1 row in another table with the values of the last record read ( the one at position 500 )
But i'm unable to sort it out, as been trying to use spring-el to find the value.
By debugging, i reached JdbcPollingChannelAdapter executeUpdateQuery method,
void executeUpdateQuery(Object obj) {
SqlParameterSource updateParameterSource = this.sqlParameterSourceFactory.createParameterSource(obj);
this.jdbcOperations.update(this.updateSql, updateParameterSource);
}
where Object obj is an ArrayList of 500 records of type A
This is my best match :
UPDATE LAST_EVENT_READ SET SEQUENCE=:#root[499].sequence, EVENT_DATE=:#[499].eventDate
Can anyone help me ?
P.S. Type A has sequence and eventDate attributes

I suggest you to use a custom SqlParameterSourceFactory and already don't rely on the SpEL:
public class CustomSqlParameterSourceFactory implements SqlParameterSourceFactory {
#Override
public SqlParameterSource createParameterSource(Object input) {
List<?> objects = (List<?>) input;
return new BeanPropertySqlParameterSource(objects.get(objects.size() - 1));
}
}
Inject this into the JdbcPollingChannelAdapter.setUpdateSqlParameterSourceFactory() and already use simple properties in the UPDATE statement:
UPDATE LAST_EVENT_READ SET SEQUENCE=:sequence, EVENT_DATE=:eventDate

Related

Cucumber V5-V6 - passing complex object in feature file step

So I have recently migrated to v6 and I will try to simplify my question
I have the following class
#AllArgsConstructor
public class Songs {
String title;
List<String> genres;
}
In my scenario I want to have something like:
Then The results are as follows:
|title |genre |
|happy song |romance, happy|
And the implementation should be something like:
#Then("Then The results are as follows:")
public void theResultsAreAsFollows(Songs song) {
//Some code here
}
I have the default transformer
#DefaultParameterTransformer
#DefaultDataTableEntryTransformer(replaceWithEmptyString = "[blank]")
#DefaultDataTableCellTransformer
public Object transformer(Object fromValue, Type toValueType) {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.convertValue(fromValue, objectMapper.constructType(toValueType));
}
My current issue is that I get the following error: Cannot construct instance of java.util.ArrayList (although at least one Creator exists)
How can I tell cucumber to interpret specific cells as lists? but keeping all in the same step not splitting apart? Or better how can I send an object in a steps containing different variable types such as List, HashSet, etc.
If I do a change and replace the list with a String everything is working as expected
#M.P.Korstanje thank you for your idea. If anyone is trying to find a solution for this here is the way I did it as per suggestions received. Inspected to see the type fromValue has and and updated the transform method into something like:
if (fromValue instanceof LinkedHashMap) {
Map<String, Object> map = (LinkedHashMap<String, Object>) fromValue;
Set<String> keys = map.keySet();
for (String key : keys) {
if (key.equals("genres")) {
List<String> genres = Arrays.asList(map.get(key).toString().split(",", -1));
map.put("genres", genres);
}
return objectMapper.convertValue(map, objectMapper.constructType(toValueType));
}
}
It is somehow quite specific but could not find a better solution :)

Table joins with PXDatabase SelectMulti

Disclaimer: I'm new to C# and Acumatica Framework
I'm looking to implement a database slot however I need to pull data from joined tables. I'm using the PXDatabase.SelectMulti method from the snippet below however, I have been unable to get it to work with joins. I also can't seem to find any examples of the method with joined tables.
Is there a way to join tables with this method or perhaps another way to query the data?
public class DatabaseSlotsExample : IPrefetchable
{
protected List<string> values = new List<string>(); // store your values here
public static List<string> Values
{
get
{
//Get the values from the slot dynamically. By providing table name, you inform system when it should reset the slot.
return PXDatabase.GetSlot<DatabaseSlotsExample>("SlotSuperKey", typeof(YourTable)).values;
}
}
public void Prefetch()
{
//read database here
foreach(PXDataRecord rec in PXDatabase.SelectMulti<YourTable>(
new PXDataField<YourTable.tableField>(), //definition for fields that system should select
new PXDataFieldValue<YourTable.tableKey>("Some Condition") //definition for restriction that you need to apply
))
{
//populate your collection from the database here
values.Add(rec.GetString(0));
}
}
}
Yes, if you use BQL.Fluent as a reference, the BQL query is also simplified. See below used on Service Orders:
foreach (PXResult<FSServiceOrder> res in
SelectFrom<FSServiceOrder>.
InnerJoin<FSAppointment>.On<FSAppointment.soRefNbr.IsEqual<FSServiceOrder.refNbr>>.
InnerJoin<FSWFStage>.On<FSWFStage.wFStageID.IsEqual<FSAppointment.wFStageID>>.
InnerJoin<FSRoom>.On<FSRoom.roomID.IsEqual<FSServiceOrder.roomID>>.
InnerJoin<FSEquipment>.On<FSEquipment.registrationNbr.IsEqual<FSRoom.descr>>.
Where<FSServiceOrder.srvOrdType.IsEqual<P.AsString>.
And<FSWFStage.wFStageCD.IsEqual<P.AsString>>>.
View.Select(this, "TO", "SCHEDULED")
{
FSServiceOrder fsServiceOrder = res.GetItem<FSServiceOrder>();
FSAppointment fsAppointment = res.GetItem<FSAppointment>();
}
Then you can use the below to pull the specific table data:

Check if ListBoxFor selectedValues is null before display in view?

I have a number of ListBoxFor elements on a form in edit mode. If there was data recorded in the field then the previously selected items are displaying correctly when the form opens. If the field is empty though an error is thrown as the items parameter cannot be null. Is there a way to check in the view and if there is data to use the ListBoxFor with the four parameters but if there isn't to only use three parameters, leaving out the selected items?
This is how I'm declaring the ListBoxFor:
#Html.ListBoxFor(model => model.IfQualityPoor, new MultiSelectList(ViewBag.IfPoor, "Value", "Text", ViewBag.IfQualityPoorSelected), new { #class = "chosen", multiple = "multiple" })
I'm using the ViewBag to pass the ICollection which holds the selected items as the controller then joins or splits the strings for binding to the model field. The MultiSelectLists always prove problematic for me.
Your question isn't entirely clear, but you're making it way harder on yourself than it needs to be using ListBoxFor. All you need for either DropDownListFor or ListBoxFor is an IEnumerable<SelectListItem>. Razor will take care of selecting any appropriate values based on the ModelState.
So, assuming ViewBag.IfPoor is IEnumerable<SelectListItem>, all you need in your view is:
#Html.ListBoxFor(m => m.IfQualityPoor, (IEnumerable<SelectListItem>)ViewBag.IfPoor, new { #class = "chosen" })
The correct options will be marked as selected based on the value of IfQualityPoor on your model, as they should be. Also, it's unnecessary to pass multiple = "multiple" in in your htmlAttributes param, as you get that just by using ListBoxFor rather than DropDownListFor.
It's even better if you use a view model and then add your options as a property. Then, you don't have to worry about casting in the view, which is always a good way to introduce runtime exceptions. For example:
public class FooViewModel
{
...
public IEnumerable<SelectListItem> IfQualityPoorOptions { get; set; }
}
Then, you set this in your action, before returning the view (instead of setting ViewBag). Finally, in your view:
#Html.ListBoxFor(m => m.IfQualityPoor, Model.IfQualityPoorOptions, new { #class = "chosen" })
Much simpler, and you'll never have any issues doing it that way.
UPDATE (based on comment)
The best way to handle flattening a list into a string for database storage is to use a special property for that, and then custom getter and setter to map to/from. For example:
public string IfQualityPoor
{
get { return IfQualityPoorList != null ? String.Join(",", IfQualityPoorList) : null; }
set { IfQualityPoorList = !String.IsNullOrWhiteSpace(value) ? value.Split(',').ToList() : null; }
}
[NotMapped]
public List<string> IfQualityPoorList { get; set; }
Then, you post to/interact with IfQualityPoorList, and the correct string will be set in the database automatically when you save.

servicestack ormlite partial update

I'm using ServiceStack Ormlite to do partial update to a database table.
I have a model:
public class Model
{
public int Id;
public int Property1;
public int Property2;
public int Property3;
}
But I only want to update fields Property1, and Property2.
Does anybody know how to do this?
Thanks.
See ServiceStack's OrmLite documentation for Update statements - they contain many different different examples of partial updates.
Here is what an ServiceStack OrmLite multiple field update with where clause looks like:
Db.UpdateOnly(
new Table_DTO_Object { Field_1 = Val_1, Field_2 = Val_2, Field_3 = Val_3 },
obj => new { obj.Field_1, obj.Field_2, obj.Field_3 },
obj => obj.Id == objId);
How to update multiple fields on a single table row / with a where clause is not immediately apparent from the ServiceStack documentation because they don't have an example with both 1) multiple fields and 2) where clause.
They have an example that updates multiple fields and they have an example of an update with a where clause - really all you need to do / I did is take the needed functionality from each example.

Rename fields in SubSonic select statement

Is there a way to rename fields when executing a select statement in SubSonic? I am using the ExecuteTypedList<MyClass> method to fill my List<MyClass> object but the properties of MyClass are not all the same as the column names from the DB table. In SQL I can do select col1 as 'FirstColumn', col2 as 'SecondColumn' from MyTable, is there a way to do something similar in SubSonic?
I believe Alias's are only available for aggregate columns.
You could just add properties of the same names as your columns to your class or a partial and map them to the properties you do use ala calculated field:
public class Songs
{
private string _songTitle;
public string SongTitle {
get { return _songTitle; }
set { _songTitle = value; }
}
public string SongName {
get { return _songTitle; }
set { _songTitle = value; }
}
}
I had the same need the other day, and added the functionality to my local copy of SubSonic. I've just submitted it a patch for it attached to this issue. Applying the patch will let you write a query like
new Select(Table1.IdColumn.AliasAs("table1ID"),
Table2.IdColumn.AliasAs("table2ID"))
.From(Table1.Schema)
.InnerJoin(Table2.Table1IdColumn, Table1.IDColumn);

Resources