I'm working with DynamoDB at the moment. I want to use a conditional write to update a record if that record has a date that is older than the new record date field.
Is there a way to compare DateTime types for conditional writes? Or is it currently only for integers, strings and streams?
Thanks.
Since you mentioned you are using ISO-8601 with the String datatype, it is easy to use the comparing operators (<, <=, etc.) in your conditional expression because of the lexicographical ordering described in this answer.
Here is a quick example where I used Java 8's time and ran it against DynamoDB Local:
import com.google.common.collect.ImmutableMap;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.spec.UpdateItemSpec;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.ConditionalCheckFailedException;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType;
import com.amazonaws.services.dynamodbv2.util.Tables;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
public class DynamoDBStackoverflow {
public static final String TABLE_NAME = "exampleTable";
private static final String HASH_KEY = "hashAttributeName";
public static void main(String[] args) {
AWSCredentials awsCredentials = new BasicAWSCredentials("key", "secret");
AmazonDynamoDB client = new AmazonDynamoDBClient(awsCredentials);
client.setEndpoint("http://localhost:4000");
DynamoDB dynamoDB = new DynamoDB(client);
if (Tables.doesTableExist(client, TABLE_NAME)) {
client.deleteTable(TABLE_NAME);
}
final CreateTableRequest createTableRequest = new CreateTableRequest()
.withTableName(TABLE_NAME)
.withKeySchema(new KeySchemaElement(HASH_KEY, KeyType.HASH))
.withAttributeDefinitions(new AttributeDefinition(HASH_KEY, ScalarAttributeType.S))
.withProvisionedThroughput(new ProvisionedThroughput(15L, 15L));
final Table table = dynamoDB.createTable(createTableRequest);
final Instant now = Instant.now();
final Instant before = now.minus(10, ChronoUnit.MINUTES).truncatedTo(ChronoUnit.MINUTES);
final Instant after = now.plus(10, ChronoUnit.MINUTES);
System.out.println("Before: " + before.toString());
System.out.println("Now: " + now.toString());
System.out.println("After: " + after.toString());
table.putItem(new Item().withPrimaryKey(HASH_KEY, "1")
.withString("dateField", before.toString()));
table.putItem(new Item().withPrimaryKey(HASH_KEY, "2")
.withString("dateField", now.toString()));
System.out.println("put items");
table.scan().forEach(System.out::println);
UpdateItemSpec updateItemSpec = new UpdateItemSpec().withPrimaryKey(HASH_KEY, "1")
.withConditionExpression("dateField < :beforeDate")
.withValueMap(ImmutableMap.of(":beforeDate", before.toString()))
.withUpdateExpression("SET dateField = :beforeDate");
try {
table.updateItem(updateItemSpec);
throw new RuntimeException();
} catch (ConditionalCheckFailedException ccfe) {
System.out.println("expected conditional write with < to fail when they are equal");
}
updateItemSpec = new UpdateItemSpec().withPrimaryKey(HASH_KEY, "2")
.withConditionExpression("dateField < :beforeDate")
.withValueMap(ImmutableMap.of(":beforeDate", before.toString()))
.withUpdateExpression("SET dateField = :beforeDate");
try {
table.updateItem(updateItemSpec);
throw new RuntimeException();
} catch (ConditionalCheckFailedException ccfe) {
System.out.println("expected conditional write with < to fail when new is before");
}
updateItemSpec = new UpdateItemSpec().withPrimaryKey(HASH_KEY, "1")
.withConditionExpression("dateField <= :beforeDate")
.withValueMap(ImmutableMap.of(":beforeDate", before.toString()))
.withUpdateExpression("SET dateField = :beforeDate");
try {
table.updateItem(updateItemSpec);
} catch (ConditionalCheckFailedException ccfe) {
System.out.println("should not happen");
throw new RuntimeException();
}
updateItemSpec = new UpdateItemSpec().withPrimaryKey(HASH_KEY, "2")
.withConditionExpression("dateField <= :afterDate")
.withValueMap(ImmutableMap.of(":afterDate", after.toString()))
.withUpdateExpression("SET dateField = :afterDate");
try {
table.updateItem(updateItemSpec);
} catch (ConditionalCheckFailedException ccfe) {
System.out.println("should not happen");
throw new RuntimeException();
}
System.out.println();
System.out.println("after all updates");
table.scan().forEach(System.out::println);
}
}
And the output:
Before: 2015-06-08T15:57:00Z
Now: 2015-06-08T16:07:08.893Z
After: 2015-06-08T16:17:08.893Z
put items
{ Item: {hashAttributeName=1, dateField=2015-06-08T15:57:00Z} }
{ Item: {hashAttributeName=2, dateField=2015-06-08T16:07:08.893Z} }
expected conditional write with < to fail when they are equal
expected conditional write with < to fail when new is before
after all updates
{ Item: {hashAttributeName=1, dateField=2015-06-08T15:57:00Z} }
{ Item: {hashAttributeName=2, dateField=2015-06-08T16:17:08.893Z} }
DynamoDB doesn't understand dates. If you save the date as long, ms/s since epoch, then you can use arithmetic <, >=, etc.
If you use a String presentation, then it all depends if you can find the right DynamoDB operator to query on two of them.
I personally use the former, thus doing it with calculus.
Related
I know there is the Instrumenter class, however this method outputs the data after the run finish. I would like to get (near) real-time data, like in the Symbolic Regression in the Demos.
Looking at its code, it seems I need to use the step method and try to imitate the runSingleSeed in Executor. Is there a better way? Some other class like Instrumenter but asynchronous. I cannot really find something similar online.
Just build a wrapper around the cycle (similar to the next one) and make it also a subject in an observer pattern.
import java.util.Properties;
import java.util.Arrays;
import java.text.DecimalFormat;
import org.moeaframework.core.Algorithm;
import org.moeaframework.core.Solution;
import org.moeaframework.core.Problem;
import org.moeaframework.core.Population;
import org.moeaframework.core.NondominatedPopulation;
import org.moeaframework.core.variable.EncodingUtils;
import org.moeaframework.core.spi.AlgorithmFactory;
import org.moeaframework.problem.misc.Kursawe;
public class Main{
public static void main(String[] args){
String algorithmName = "NSGAII";
Properties properties = new Properties();
properties.setProperty("populationSize", "100"); // to change properties
Problem problem = new Kursawe();
Algorithm algorithm = AlgorithmFactory.getInstance()
.getAlgorithm(algorithmName, properties, problem);
int maxGenerations = 100;
int generation = 0;
while( generation < maxGenerations ){
if( generation % 10 == 1 ){
System.out.println("Generation " + generation);
NondominatedPopulation paretoFront = algorithm.getResult();
// metrics
System.out.print("One of the pareto front: ");
System.out.println(toString(paretoFront.get(0)));
}
algorithm.step();
generation++;
}
algorithm.terminate();
System.out.println("Parento Front:");
for(Solution solution: algorithm.getResult()){
System.out.println(toString(solution));
}
export(algorithm.getResult());
}
private static String toString(Solution solution){
StringBuilder out = new StringBuilder();
double[] variables = EncodingUtils.getReal(solution);
double[] objectives = solution.getObjectives();
out.append("f");
out.append(doubleArrayToString(variables));
out.append(" = ");
out.append(doubleArrayToString(objectives));
return out.toString();
}
private static String doubleArrayToString(double[] array){
DecimalFormat format = new DecimalFormat("+#,##0.00;-#");
StringBuilder out = new StringBuilder();
out.append("[");
for(int i = 0; i < array.length-1; i++){
out.append(format.format(array[i]));
out.append(", ");
}
out.append(format.format(array[array.length-1]));
out.append("]");
return out.toString();
}
private static void export(Population population){
System.out.println();
for(Solution solution: population){
double[] objectives = solution.getObjectives();
System.out.println(String.format("%.3f,%.3f", objectives[0], objectives[1]));
}
}
}
Another option for the one indicated by Black Arrow, if you are using multithread, is to extentend AlgorithmFactory. For example:
public class MyAlgorithmFactory extends AlgorithmFactory {
private static Algorithm algorithm;
public Algorithm getGeneratedAlgorithm() {
return this.algorithm;
}
#Override
public Algorithm getAlgorithm(String name, Properties properties, Problem problem){
this.algorithm = super.getAlgorithm(name, properties, problem);
return algorithm;
}
}
Then you use this Factory on your Executor, for example:
MyAlgorithmFactory af = new MyAlgorithmFactory();
Executor executor = new Executor()
.usingAlgorithmFactory(af)
.withAlgorithm("NSGAII") //
.withProblem(yourProblemHere) //
.withMaxEvaluations(10000);
After this you can start the Executor on a separated thread, and call af.getGeneratedAlgorithm() to get the instance of Algorithm initialized by the Executor. From this Algorithm you can get, while the Executor is still running, the actual NondominatedPopulation to calc statistics.
I think I need some feedback on my collection classes - still learning typescript and javascript and these implementations can surely be improved. I am looking forward to any suggestion. I think I do use the generic types in a useful way, any advice here would be appreciated.
The answer I am looking for most is removing the duplicate IHashTable definition from the end of both snippets and moving it to its own file, I cannot get that done it seems. I am even unsure if this IS an interface in the first place. It compiles and works this way, as far as I can see.
The collection types are incomplete and only define the basic most function at the moment. Once I am sure I use the language and its features correct the other functions should not be too difficult.
Here is my HashSet:
import { IHashable } from "./IHashable"
export class HashSet<T extends IHashable> {
private _items: HashTable<T>;
public constructor() {
this._items = {};
}
public Add(key: T): void {
let str: string = key.GetHash();
if (this._items[str] == null) {
this._items[str] = key;
}
else {
throw new RangeError("Key '" + str + "' already exists.");
}
}
public Contains(key: T): boolean {
let str: string = key.GetHash();
return this._items[str] != null;
}
}
interface HashTable<T> {
[key: string]: T;
}
I wonder if I can avoid the checking-before-adding in a way. The javascript-dictionary this relies on does allow duplicates, so to avoid them there is no other way than to check myself?
This is my Dictionary:
import { IHashable } from "./IHashable"
export class Dictionary<T1 extends IHashable, T2> {
private _items: HashTable<KeyValuePair<T1, T2>>;
public constructor() {
this._items = {};
}
public Add(key: T1, value: T2) {
let str: string = key.GetHash();
if (this._items[str] == null) {
let kvp: KeyValuePair<T1, T2> = new KeyValuePair(key, value);
this._items[str] = kvp;
}
else {
throw new RangeError("Key '" + str + "' already exists.");
}
}
public ContainsKey(key: T1): boolean {
let str: string = key.GetHash();
return this._items[str] != null;
}
public Get(key: T1): T2 {
let str: string = key.GetHash();
let kvp: KeyValuePair<T1, T2> = this._items[str];
if (kvp == null) throw new RangeError("Key '" + str + "' not found")
return kvp.Value;
}
}
export class KeyValuePair<T1 extends IHashable, T2> {
private _key: T1;
private _value: T2;
public get Key(): T1 { return this._key; }
public get Value(): T2 { return this._value; }
public constructor(key: T1, value: T2) {
this._key = key;
this._value = value;
}
}
interface HashTable<T> {
[key: string]: T;
}
Both rely on a definition of IHashable (hashABLE and hashTABLE: I should find other names.)
export interface IHashable {
GetHash(): string;
}
The dictionary looks a bit strange, it "wraps" my dictionary into a new type KeyValuePair and then uses this in the javascript dictionary. What I hope to gain by doing this is get my own type for key, in and out, as long as it offers a string by which it can be indexed. - No idea if that makes sense or is completly wrong.
What I am missing is the count of items in the collection, a way to remove items, and a way to iterate over the keys and the values.
Regarding iterating over I will post another question with my implementation of a list and a ForEach over it, hoping iterating the keys or values might be possible in the same way.
Probably the most important question I forgot here: How could the GetHash-Method be build for an own class? I was going to have a static number on my classes, and count up by 1 in the constructor before assign this number to each instance. This would guarantee uniqueness... is there something better?
Thanks for any tip!
Ralf
I have created a method to dynamically build rest URI based on Bean properties, initially it was imperative then I have refactored it to functional style, it's my first time doing functional programming.
both imperative and functional are working as expected, but I am not happy by the functional readability, functional seams an over kill for this method or it could be because i am still a novice functional programmer!
How would you refactor this method to more clean functional way?
Or would you keep it Imperative?
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.lang.reflect.Method;
import org.springframework.beans.BeanUtils;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.util.UriComponentsBuilder;
public String functionalBuildRestUri() throws Exception {
final UriComponentsBuilder uriBuilder = UriComponentsBuilder.newInstance().scheme("https")
.host("foo.com").path("/offers");
//here is the functional
List<PropertyDescriptor> propDescList = Arrays.asList(BeanUtils.getPropertyDescriptors(getClass()));
//this part is readable and precis, but to enable it had to add 4 methods
propDescList.stream().filter(notClassProp())
.filter(notNullPropValue())
.collect(Collectors.toMap(PropertyDescriptor::getName, propValue()))//conversion to map doesn't feel good to me how can I avoid it?
.forEach(buildRestParam(uriBuilder));
return uriBuilder.build().toUriString();
}
public String imperativeBuildRestUri() throws Exception {
final UriComponentsBuilder uriBuilder = UriComponentsBuilder.newInstance().scheme("https")
.host("foo.com").path("/offers");
PropertyDescriptor[] propDescArray = BeanUtils.getPropertyDescriptors(getClass());
for (PropertyDescriptor propDesc : propDescArray) {
String propName = propDesc.getName();
if (!propName.equals("class")) {
Method getPropMethod = propDesc.getReadMethod();
Object propValue = getPropMethod.invoke(this);
if (propValue != null) {
if(propValue instanceof Date){
String dateStr = new SimpleDateFormat(DATE_FORMAT).format((Date)propValue);
uriBuilder.queryParam(propName, ":"+dateStr);
}else{
uriBuilder.queryParam(propName, propValue);
}
}
}
}
return uriBuilder.build().toUriString();
}
All Those methods has been added after functional refactoring
// I couldn't avoid being imperative here, how can we refactor it to more functional style
private BiConsumer<String, Object> buildRestParam(final UriComponentsBuilder uriBuilder) {
return (propName, propValue) -> {
if (propValue instanceof Date) {
String dateStr = new SimpleDateFormat(DATE_FORMAT).format((Date) propValue);
uriBuilder.queryParam(propName, ":" + dateStr);
} else {
uriBuilder.queryParam(propName, propValue);
}
};
}
private Predicate<? super PropertyDescriptor> notNullPropValue() {
return propDesc -> {
return propValue().apply(propDesc) != null;
};
}
private Predicate<? super PropertyDescriptor> notClassProp() {
return propDesc -> {
return !propDesc.getName().equals("class");
};
}
private Function<? super PropertyDescriptor, ? extends Object> propValue() {
return (propDesc) -> {
try {
return propDesc.getReadMethod().invoke(HotelOfferSearchCommand.this);
} catch (IllegalAccessException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (IllegalArgumentException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
};
}
Most of the verbosity of the new code has nothing to do with functional programming. You have refactored the code to put every lambda expression into a method of it’s own, which, of course, destroys one of the main advantages of lambda expressions, the compactness. Even if code is complex enough to justify the creation of a method, that method should perform actual work, then, you could use a method reference where a function is required.
The methods further suffer from an unnecessary (even discouraged, as being in a return type) use of wild cards. You also used the verbose syntax parameter -> { return expression; } where parameter -> expression would be possible.
There are other issues, like unnecessarily creating a distinct catch clause for each exception type, when all do the same or wrapping the array into a List before creating the Stream instead of streaming over the array directly or having code duplication, the last point applies to both, the imperative variant and the functional one.
You can just write:
public String functionalBuildRestUri() throws Exception {
final UriComponentsBuilder uriBuilder = UriComponentsBuilder.newInstance()
.scheme("https").host("foo.com").path("/offers");
Function<PropertyDescriptor, Object> propValue = propDesc -> {
try { return propDesc.getReadMethod().invoke(HotelOfferSearchCommand.this); }
catch(ReflectiveOperationException e) { throw new RuntimeException(e); }
};
Arrays.stream(BeanUtils.getPropertyDescriptors(getClass()))
.filter(propDesc -> !propDesc.getName().equals("class"))
.filter(propDesc -> propValue.apply(propDesc) != null)
.forEach(propDesc -> {
Object value = propValue.apply(propDesc);
if (value instanceof Date)
value = ":"+new SimpleDateFormat(DATE_FORMAT).format(value);
uriBuilder.queryParam(propDesc.getName(), value);
});
return uriBuilder.build().toUriString();
}
without any extra method.
This might not be the best option, as there is indeed one flaw, the absence of a tuple or pair type to hold two values to be passed through the stream. By using Map.Entry as a stand-in, but not populating a Map, we can express the operation as
public String functionalBuildRestUri() throws Exception {
final UriComponentsBuilder uriBuilder = UriComponentsBuilder.newInstance()
.scheme("https").host("foo.com").path("/offers");
Function<PropertyDescriptor, Object> propValue = propDesc -> {
try { return propDesc.getReadMethod().invoke(HotelOfferSearchCommand.this); }
catch(ReflectiveOperationException e) { throw new RuntimeException(e); }
};
Arrays.stream(BeanUtils.getPropertyDescriptors(getClass()))
.filter(propDesc -> !propDesc.getName().equals("class"))
.map(propDesc -> new AbstractMap.SimpleImmutableEntry<>(
propDesc.getName(), propValue.apply(propDesc)))
.filter(entry -> entry.getValue() != null)
.forEach(entry -> {
Object value = entry.getKey();
if (value instanceof Date)
value = ":"+new SimpleDateFormat(DATE_FORMAT).format(value);
uriBuilder.queryParam(entry.getKey(), value);
});
return uriBuilder.build().toUriString();
}
or, alternatively
Arrays.stream(BeanUtils.getPropertyDescriptors(getClass()))
.filter(propDesc -> !propDesc.getName().equals("class"))
.map(propDesc -> new AbstractMap.SimpleImmutableEntry<>(
propDesc.getName(), propValue.apply(propDesc)))
.filter(entry -> entry.getValue() != null)
.map(e -> e.getValue() instanceof Date?
new AbstractMap.SimpleImmutableEntry<>(e.getKey(),
":"+new SimpleDateFormat(DATE_FORMAT).format(e.getValue())):
e)
.forEach(entry -> uriBuilder.queryParam(entry.getKey(), entry.getValue()));
With these two variants, the propValue function is evaluated only once per element instead of two times as in the first variant and your original code, where both, the check for null property value and the terminal operation evaluated it.
Note that there’s still room for improvement, e.g. there’s no reason to add the ":" after the format operation when you could make the colon a part of the format pattern string in the first place.
Whether this is an improvement over the loop, is something you have to decide yourself. Not every code has to be rewritten to a functional style. At least, as shown by the the examples above, it doesn’t have to be bigger than the imperative code…
How to verify an attribute whether it present in table or not without using scan in dynamodb?
In my usecase, From client side, The customer request with their Customer_id for knowing the values of the product. In server side, have to check whether the entered customer_id already present in DynamoDB table or not. If not, have to make a new entry.
How can I implement this case without using SCAN operation to the table?
It sounds to me that you want to do a conditional PutItem on this table: put the item into the table if there is not another item with the same customer_id. This is easy enough to do because the customer_id is the hash key of the table. From the PutItem documentation:
Note
To prevent a new item from replacing an existing item, use a conditional put operation with ComparisonOperator set to NULL for the
primary key attribute, or attributes.
Here is a quick example I coded up using the Dynamo DB document API in the Java SDK and running against DynamoDB Local:
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Expected;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.ConditionalCheckFailedException;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType;
import com.amazonaws.services.dynamodbv2.util.Tables;
public class StackOverflow {
private static final String EXAMPLE_TABLE_NAME = "example_table";
public static void main(String[] args) {
AmazonDynamoDB client = new AmazonDynamoDBClient(new BasicAWSCredentials("accessKey", "secretKey"));
client.setEndpoint("http://localhost:4000");
DynamoDB dynamoDB = new DynamoDB(client);
if (Tables.doesTableExist(client, "example_table")) client.deleteTable(EXAMPLE_TABLE_NAME);
// Create table with hash key 'customer_id'
CreateTableRequest createTableRequest = new CreateTableRequest();
createTableRequest.withTableName(EXAMPLE_TABLE_NAME);
createTableRequest.withKeySchema(new KeySchemaElement("customer_id", KeyType.HASH));
createTableRequest.withAttributeDefinitions(new AttributeDefinition("customer_id", ScalarAttributeType.S));
createTableRequest.withProvisionedThroughput(new ProvisionedThroughput(15l, 15l));
dynamoDB.createTable(createTableRequest);
Tables.waitForTableToBecomeActive(client, EXAMPLE_TABLE_NAME);
Table exampleTable = dynamoDB.getTable(EXAMPLE_TABLE_NAME);
exampleTable.putItem(new Item()
.withPrimaryKey("customer_id", "ABCD")
.withString("customer_name", "Jim")
.withString("customer_email", "jim#gmail.com"));
System.out.println("After Jim:");
exampleTable.scan()
.forEach(System.out::println);
System.out.println();
try {
exampleTable.putItem(new Item()
.withPrimaryKey("customer_id", "EFGH")
.withString("customer_name", "Garret")
.withString("customer_email", "garret#gmail.com"), new Expected("customer_id").notExist());
} catch (ConditionalCheckFailedException e) {
System.out.println("Conditional check failed!");
}
System.out.println("After Garret:");
exampleTable.scan()
.forEach(System.out::println);
System.out.println();
try {
exampleTable.putItem(new Item()
.withPrimaryKey("customer_id", "ABCD")
.withString("customer_name", "Bob")
.withString("customer_email", "bob#gmail.com"), new Expected("customer_id").notExist());
} catch (ConditionalCheckFailedException e) {
System.out.println("Conditional check failed!");
}
System.out.println("After Bob:");
exampleTable.scan()
.forEach(System.out::println);
}
}
Output:
After Jim:
{ Item: {customer_email=jim#gmail.com, customer_name=Jim, customer_id=ABCD} }
After Garret:
{ Item: {customer_email=garret#gmail.com, customer_name=Garret, customer_id=EFGH} }
{ Item: {customer_email=jim#gmail.com, customer_name=Jim, customer_id=ABCD} }
Conditional check failed!
After Bob:
{ Item: {customer_email=garret#gmail.com, customer_name=Garret, customer_id=EFGH} }
{ Item: {customer_email=jim#gmail.com, customer_name=Jim, customer_id=ABCD} }
How can I populate a list with data from a SQLite database in my Blackberry application? I can view the list, but I can see only one item which is the last item from my database table in the list. Below is the code:
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.database.Database;
import net.rim.device.api.database.DatabaseFactory;
import net.rim.device.api.database.Row;
import net.rim.device.api.database.Statement;
import net.rim.device.api.io.URI;
class ListFieldScreen extends MainScreen
{
Database d;
public ListFieldScreen()
{
final ObjectListField list = new ObjectListField();
try
{
URI myURI=URI.create("file:///SDCard/Databases/MyTestDatabase.db");
d=DatabaseFactory.open(myURI);
Statement st=d.createStatement("SELECT eng FROM English");
st.prepare();
net.rim.device.api.database.Cursor c=st.getCursor();
Row r;
while(c.next())
{
r=c.getRow();
String w=r.getString(0);
String[] t={w};
list.set(t);
add(list);
}
st.close();
d.close();
}
catch ( Exception e ) {
e.printStackTrace();
}
}
}
Try like this:
First declare as
public Vector tableVector;
public ObjectListField list;
and call this below code in separate method;
tableVector=new Vector();//Declare this before the method;
try
{
//Uri creation
Statement st=LoadingScreen.database.createStatement("YOUR Statement");
st.prepare();
Cursor c = st.getCursor();
Row r;
while(c.next())
{
r = c.getRow();
tableVector.addElement(r.getString(0));
}
st.execute();
st.close();
}
catch(Exception e)
{
//Exception;
}
After complete this method; show the data as...
String ar[]=new String[tableVector.size];
for(int i=0;i<tableVector.size;i++)
{
ar[i]=tableVector.elementAt(i).toString();
}
list.set(ar);
add(list);
I suppose you need to specify number of items you want to show in the list - I mean number of ites from db -