How to increase the value of a text by my database - database

I want to change the value of a variable called "value" which represent the shown value in the screen according to my database, here is my code
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val mViewModel = ViewModelProvider(this).get(ExpenseCalculatorViewModel::class.java)
binding.categoryName.text = args.category
val viewModel = ViewModelProvider(this).get(CategoriesViewModel::class.java)
when (binding.categoryName.text) {
getString(R.string.restaurant) -> {
viewModel.readRestaurantData.observe(viewLifecycleOwner, {
var value = 0
for (i in it.indices) {
value += it[i].restaurant
}
binding.totalNumber.text = value.toString()
})
}
please I need a useful answer and thanks for your patience

You need to perform an update query. Using ROOM for your SQLITE, you create the update query on your DAO class, you can call RestaurantDao. Allocate all your queries there such as update, delete, insert, etc.
Example: (modify the names of the table and variables according to your table structure.
#Query("UPDATE my_restaurant_table SET value=:value " +
"WHERE id=:id"
) public abstract void updateRestaurant(
long id,
String value
);

Related

Summary of ArrayList ordering in Kotlin (Android)

I am trying to provide a summary of items within an ArrayList (where order matters). Basically, I am setting up an exercise plan with two different types of activities (Training and Assessment). I then will provide a summary of the plan after adding each training/assessment to it.
The structure I have is something along the lines of:
exercisePlan: [
{TRAINING OBJECT},
{TRAINING OBJECT},
{ASSESSMENT OBJECT},
{TRAINING OBJECT}
]
What I want to be able to do is summarise this in a format of:
2 x Training, 1 x Assessment, 1 x Training, which will be displayed in a TextView in a Fragment. So I will have an arbitrarily long string that details the structure and order of the exercise plan.
I have tried to investigate using a HashMap or a plain ArrayList, but it seems pretty messy so I'm looking for a much cleaner way (perhaps a MutableList). Thanks in advance!
ArrayList is just a specific type of MutableList. It's usually preferable to use a plain List, because mutability can make code a little more complex to work with and keep robust.
I'd create a list of some class that wraps an action and the number of consecutive times to do it.
enum class Activity {
Training, Assessment
}
data class SummaryPlanStep(val activity: Activity, val consecutiveTimes: Int) {
override fun toString() = "$consecutiveTimes x $activity"
}
If you want to start with your summary, you can create it and later convert it to a plain list of activities like this:
val summary: List<SummaryPlanStep> = listOf(
SummaryPlanStep(Activity.Training, 2),
SummaryPlanStep(Activity.Assessment, 1),
SummaryPlanStep(Activity.Training, 1),
)
val plan: List<Activity> = summary.flatMap { List(it.consecutiveTimes) { _ -> it.activity } }
If you want to do it the other way around, it's more involved because I don't think there's a built-in way to group consecutive duplicate elements. You could a write a function for that.
fun <T> List<T>.groupConsecutiveDuplicates(): List<Pair<T, Int>> {
if (isEmpty()) return emptyList()
val outList = mutableListOf<Pair<T, Int>>()
var current = first() to 1
for (i in 1 until size) {
val item = this[i]
current = if (item == current.first)
current.first to (current.second + 1)
else {
outList.add(current)
item to 1
}
}
outList.add(current)
return outList
}
val plan: List<Activity> = listOf(
Activity.Training,
Activity.Training,
Activity.Assessment,
Activity.Training
)
val summary: List<SummaryPlanStep> = plan.groupConsecutiveDuplicates().map { SummaryPlanStep(it.first, it.second) }
This is what I have set up to work for me at the moment:
if (exercisePlanSummary.isNotEmpty() && exercisePlanSummary[exercisePlanSummary.size - 1].containsKey(trainingAssessment)) {
exercisePlanSummary[exercisePlanSummary.size - 1][trainingAssessment] = exercisePlanSummary[exercisePlanSummary.size - 1][trainingAssessment]!! + 1
} else {
exercisePlanSummary.add(hashMapOf(trainingAssessment to 1))
}
var textToDisplay = ""
exercisePlanSummary.forEach {
textToDisplay = if (textToDisplay.isNotEmpty()) {
textToDisplay.plus(", ${it.values.toList()[0]} x ${it.keys.toList()[0].capitalize()}")
} else {
textToDisplay.plus("${it.values.toList()[0]} x ${it.keys.toList()[0].capitalize()}")
}
}
where trainingAssessment is a String of "training" or "assessment". exercisePlanSummary is a ArrayList<HashMap<String, Int>>.
What #Tenfour04 has written above is perhaps more appropriate, and a cleaner way of implementing this. But my method is quite simple.

FOR statement to query a SQL Server

I want to create a query against a database with a for statement (in C#)
something like this:
List<object> data = new List<object>();
for(int i = 0; i < executeScalar("SELECT COUNT(*) FROM mytable"); i++)
{
List[i] = executeRead("SELECT rownumber(i) From mytable");
// or
executeUpdate("UPDATE mytable SET ... inrownumber(i)",List[i])
}
and the question is: is there any function to use for this "rownumber(i)" and "inrownumber(i)"?
I know I can do it like this
List[i] = executeRead("SELECT * From mytable WHERE ROW_NUMBER() = " + i);
and
executeUpdate("UPDATE mytable SET ... WHERE ROW_NUMBER() = " + i,List[i])
but if I do that - the database will search in all the table each time to find one item, so if I have 100 items, the database will pass on 10,000 items. and I wont that each time the database go directly to the row, so it pass only 100 items in all the for statement
Do you know any way do do it?
(I need it because in my program - the developer assumed that all the data is in the list, and he take them with a for statement and by index, and do "Add" and "Insert" and so on, and I don't wont to change all the program)
Thanks
Assuming you have your data stored in a generic list called places then
Using (SqlConnection cn = GetMyDbConnectionHere())
{
Using(SqlCommand cmd = new SqlCommand("dbo.UpdatePlace", cn)
{
// Create your parameters for the command here - e.g. p_PlaceName
foreach(Place place in places)
{
if(place.HasChanged)
{
p_PrimaryKey.value = place.primaryKey;
p_PlaceName.value = place.placeName;
p_PlaceLat.value = place.lat;
// And so on and so forth
cmd.ExecuteNonQuery();
}
}
}
}
All this code is straight off the top of my head and typed directly into SO on the web page - so I make no guarantee as to it being fully functional - but it should at least get you going... In addition there's zero error handling here - also a major no-no.

Using LINQ to find Excel columns that don't exist in array?

I have a solution that works for what I want, but I'm hoping to get some slick LINQ types to help me improve what I have, and learn something new in the process.
The code below is used verify that certain column names exist on a spreadsheet. I was torn between using column index values or column names to find them. They both have good and bad points, but decided to go with column names. They'll always exist, and sometimes in different order, though I'm working on this.
Details:
GetData() method returns a DataTable from the Excel spreadsheet. I cycle through all the required field names from my array, looking to see if it matches with something in the column collection on the spreadsheet. If not, then I append the missing column name to an output parameter from the method. I need both the boolean value and the missing fields variable, and I wasn't sure of a better way than using the output parameter. I then remove the last comma from the appended string for the display on the UI. If the StringBuilder object isn't null (I could have used the missingFieldCounter too) then I know there's at least one missing field, bool will be false. Otherwise, I just return output param as empty, and method as true.
So, Is there a more slick, all-in-one way to check if fields are missing, and somehow report on them?
private bool ValidateFile(out string errorFields)
{
data = GetData();
List<string> requiredNames = new [] { "Site AB#", "Site#", "Site Name", "Address", "City", "St", "Zip" }.ToList();
StringBuilder missingFields = null;
var missingFieldCounter = 0;
foreach (var name in requiredNames)
{
var foundColumn = from DataColumn c in data.Columns
where c.ColumnName == name
select c;
if (!foundColumn.Any())
{
if (missingFields == null)
missingFields = new StringBuilder();
missingFieldCounter++;
missingFields.Append(name + ",");
}
}
if (missingFields != null)
{
errorFields = missingFields.ToString().Substring(0, (missingFields.ToString().Length - 1));
return false;
}
errorFields = string.Empty;
return true;
}
Here is the linq solution that makes the same.
I call the ToArray() function to activate the linq statement
(from col in requiredNames.Except(
from dataCol in data
select dataCol.ColumnName
)
select missingFields.Append(col + ", ")
).ToArray();
errorFields = missingFields.ToString();
Console.WriteLine(errorFields);

IBATIS - Insert dynamic HashMap from Spring to Oracle

Some background on the issue. From the front end, I have two select boxes with the multiple property. One box is for approved items, the other is for ignored items. I place these into a Map with the key being the company's UID, and the value either being "Y" or "N" depending on which box the UID is in. Inserting HashMap Values to a table using ibatis provided some assistance, but the answer involved manually putting the entries, where as I am dynamically creating the map, so not sure what the keys will be. Below is the code for the Java:
// Set up the map object for the back end
Map<Integer, String> posMap = new HashMap<Integer, String>();
// Get the approved mailers
String[] mailerList = request.getParameterValues("approved");
if (mailerList != null && mailerList.length > 0)
{
for(String mailer : mailerList)
{
posMap.put(Integer.parseInt(mailer), "Y");
}
}
// reset the mailerList
mailerList = null;
// get the ignored mailers
mailerList = request.getParameterValues("ignored");
if (mailerList != null && mailerList.length > 0)
{
for(String mailer : mailerList)
{
posSampleMap.put(Integer.parseInt(mailer), "N");
}
}
// only update POS if the map is not empty
if(!posMap.isEmpty())
{
updateMapper.updatePOSSampling(posMap);
}
Normally, I would have something like this in the mapper.xml file:
<update id="updatePOSSampling" parameterType="hashmap">
UPDATE <table_name>
SET sampling_enabled = ${myMapValue}
WHERE mailer_name = ${myMapKey}
</update>
In the link I provided, they were manually putting in the keys and values, and as such, the example IBATIS could refer to the key. Since I'm not sure what my key is, what would be the best way to generate this query? I've got a temporary workaround of sending a two dimension array, but I feel using a Map DO would be a better way. Thanks in advance for any assistance.

Querying a timestamp column from LINQ to SQL

My table has a timestamp column named "RowVer" which LINQ maps to type System.Data.Linq.Binary. This data type seems useless to me because (unless I'm missing something) I can't do things like this:
// Select all records that changed since the last time we inserted/updated.
IEnumerable<UserSession> rows = db.UserSessions.Where
( usr => usr.RowVer > ???? );
So, one of the solutions I'm looking at is to add a new "calculated column" called RowTrack which is defined in SQL like this:
CREATE TABLE UserSession
(
RowVer timestamp NOT NULL,
RowTrack AS (convert(bigint,[RowVer])),
-- ... other columns ...
)
This allows me to query the database like I want to:
// Select all records that changed since the last time we inserted/updated.
IEnumerable<UserSession> rows = db.UserSessions.Where
( usr => usr.RowTrack > 123456 );
Is this a bad way to do things? How performant is querying on a calculated column? Is there a better work-around?
Also, I'm developing against Sql Server 2000 for ultimate backwards compatibility, but I can talk the boss into making 2005 the lowest common denominator.
AS Diego Frata outlines in this post there is a hack that enables timestamps to be queryable from LINQ.
The trick is to define a Compare method that takes two System.Data.Linq.Binary parameters
public static class BinaryComparer
{
public static int Compare(this Binary b1, Binary b2)
{
throw new NotImplementedException();
}
}
Notice that the function doesn't need to be implemented, only it's name (Compare) is important.
And the query will look something like:
Binary lastTimestamp = GetTimeStamp();
var result = from job in c.GetTable<tblJobs>
where BinaryComparer.Compare(job.TimeStamp, lastTimestamp)>0
select job;
(This in case of job.TimeStamp>lastTimestamp)
EDIT:
See Rory MacLeod's answer for an implementation of the method, if you need it to work outside of SQL.
SQL Server "timestamp" is only an indicator that the record has changed, its not actually a representation of Date/Time. (Although it is suppose to increment each time a record in the DB is modified,
Beware that it will wrap back to zero (not very often, admittedly), so the only safe test is if the value has changed, not if it is greater than some arbitrary previous value.
You could pass the TimeStamp column value to a web form, and then when it is submitted see if the TimeStamp from the form is different to the value in the current record - if its is different someone else has changed & saved the record in the interim.
// Select all records that changed since the last time we inserted/updated.
Is there a better work-around?
Why not have two columns, one for createddate another for lastmodifieddate. I would say that is more traditional way to handle this scenario.
Following on from jaraics' answer, you could also provide an implementation for the Compare method that would allow it to work outside of a query:
public static class BinaryExtensions
{
public static int Compare(this Binary b1, Binary b2)
{
if (b1 == null)
return b2 == null ? 0 : -1;
if (b2 == null)
return 1;
byte[] bytes1 = b1.ToArray();
byte[] bytes2 = b2.ToArray();
int len = Math.Min(bytes1.Length, bytes2.Length);
int result = memcmp(bytes1, bytes2, len);
if (result == 0 && bytes1.Length != bytes2.Length)
{
return bytes1.Length > bytes2.Length ? 1 : -1;
}
return result;
}
[DllImport("msvcrt.dll")]
private static extern int memcmp(byte[] arr1, byte[] arr2, int cnt);
}
The use of memcmp was taken from this answer to a question on comparing byte arrays. If the arrays aren't the same length, but the longer array starts with the same bytes as the shorter array, the longer array is considered to be greater than the shorter one, even if the extra bytes are all zeroes.

Resources