I use RecordStore to store my data.
I know when we store data in RecordStore, it automatically generates a record id for each record.
But how can I set the record id by myself? Or how can I get the record id?
Because I want to use the recordstore.setRecord(..) method to update my recordstore.
But when I use RecordEnumeration to fetch RecordStore and use method nextRecordId(), it just shows odd or even ids. I mean when I have 8 records, it just prints out only odd or even records like
2 4 6 8
My code:
handleRecord.openRecordStore(handleRecord.getRecordName());
RecordEnumeration re;
try {
int rc = handleRecord.getRecordStore().getNumRecords();
re = hrs.getRcs().enumerateRecords(null, null, true);
while(re.hasNextElement()) {
int rid = re.nextRecordId();
System.out.println(rid);
}
} catch(Exception e) {
System.out.println(e.toString());
}
MIDP API doesn't have method to set record id by yourself.
See RecordStore API documentation for explanation how this is supposed to work.
"Records are uniquely identified within a given record store by their recordId, which is an integer value. This recordId is used as the primary key for the records. The first record created in a record store will have recordId equal to one (1). Each subsequent record added to a RecordStore will be assigned a recordId one greater than the record added before it. That is, if two records are added to a record store, and the first has a recordId of 'n', the next will have a recordId of 'n + 1'..."
The code that iterates the store appears OK:
re = hrs.getRcs().enumerateRecords(null, null, true);
while(re.hasNextElement()) {
int rid = re.nextRecordId();
System.out.println(rid);
}
if you're getting only odd or even record like 2-4-6... or 1-3-5... printed as a result, first thing to check is whether you somehow removed records that are "missing" - this could be done eg using RecordStore.getVersion method:
"Each time a record store is modified (by addRecord, setRecord, or deleteRecord methods) its version is incremented. This can be used by MIDlets to quickly tell if anything has been modified..."
Related
I have a Purchase Order content type in my Orchard application. Among other properties it has a PurchaseOrderNumber. The purchase order number is assigned when the user saves the purchase order for the first time. I use a custom controller and views for implementing the purchase order CRUD operations.
I have a purchase order number definition part which is attached to a company content type where the next purchase order number, a prefix and padding is saved. So when the system generates the next purchase order number, the prefix (e.g. PO) is used together with the next number (e.g. 123) and the padding (e.g. 5) to generate a string - e.g. PO00123.
When the purchase order number is generated the next purchase order number stored in the purchase order definition part attached to the company content item is incremented and saved so that when a user creates another purchase order it will be assigned the next number.
My challenge here is to prevent duplicate purchase order numbers from being assigned if two users create a new purchase order at the same time.
I was thinking of creating an ISingletonDependency that uses lock (_lock) {...} to wrap code that will generate the next number. This way multiple request can ask for the next number and always get the next unique number. How do I implement this though? I can't figure out how to get access to an IContentManager that has its own database transaction.
Or is there a different pattern that I should rather use?
I figured it out after looking at the Orchard.Tasks.Locking.Services.DistributedLockService class. You need to take a dependency on ILifetimeScope and then resolve ITransactionManager and IContentManager.
lock (_lock) {
using (var childLifetimeScope = _lifetimeScope.BeginLifetimeScope()) {
var transactionManager = childLifetimeScope.Resolve<ITransactionManager>();
var contentManager = childLifetimeScope.Resolve<IContentManager>();
try {
transactionManager.RequireNew(IsolationLevel.Serializable);
var contentItem = contentManager.GetLatest(contentItemId);
var number = CompileNewNumber(contentItem);
contentManager.Publish(contentItem);
return number;
}
catch (Exception exception) {
Logger.Error(exception, "Error compiling next number.");
transactionManager.Cancel();
return "";
}
}
}
In the following instance, I have tried to simplify an issue to root components.
I've got a very simple SQL Azure database where I created a test table called Table1. Azure creates an ID field with Is Required, Is Primary Key checked. It will NOT allow to check the box Is Identity. There are a couple of other fields which are simply required.
In my VS2012 Project, I have created an LinqToSql Class which created a ProductionDataClasses1.dbml object.
I simply want to add a record to this table thru the method shown below. From what I am reading, ID would be set during the SubmitChanges() after InsertOnSubmit(NewRecord) is specified.
It does work the first time but value is set to zero. On subsequent save, I get an exception (basically it a duplicate record because ID=0 already exists).
To put this into context, I have included some sample code below. The idea is to first check if the record exists and update. If not, I want to add a record.
My question is... Do I need to manually set ID? If so, how do I set the value to an int and how to a retrieve the next value. I tried changing to a Guid but not allowed.
Here is my code sample:
public bool AddTestRecord(string someValue)
{
ProductionDataClasses1DataContext context = new ProductionDataClasses1DataContext();
try
{
var ExistingRecord = context.Table1s.SingleOrDefault(c => c.TextKey == someValue);
if (ExistingRecord == null)
{
var NewRecord = new Table1();
// NewRecord.ID = ???? ; How Do I Manually Set. It is getting set to 0 causing a duplicate value exception
NewRecord.TextKey = someValue;
NewRecord.AnotherValue = DateTime.Now.ToShortTimeString();
context.Table1s.InsertOnSubmit(NewRecord);
}
else
{
ExistingRecord.AnotherValue = DateTime.Now.TimeOfDay.ToString();
}
context.SubmitChanges();
return true;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return false;
context.SubmitChanges();
}
}
I would suggest manually running a SQL script to alter the table and make the column an identity. Look at this answer
Adding an identity to an existing column
Thanks for your reply.
I just was finally able to make this work on a new table and will try to follow along your instructions to make modifications to my real table. My code (as written above) was OK so the issue is in the SQL Azure table definition.
I found the issue is that when you create a new table in SQL Azure, it creates a table with three fields, ID, Column1, Column2. By default, ID is set as the Primary Key but none are checked as Is Identity.
To make this work, I made ID the Is Identity and unchecked PrimaryKey and Column1 the In Primary Key. Thus when a new record is saved, the ID is set and Column1 is checked to make sure it is not already in the system. I had to do this when the table was first created. Once saved, it would not allow me to change.
Afterwards, I updated my Linq To SQL class and dropped the new table in. I noted that now the AutoGenerated Value on ID and PrimaryKey on Column1 was set and my code worked.
I'm relatively new to Apex, but I have some questions about a batch job that I am creating. I want to make a query with a subquery (please see the code). Every Portal_c can have more than 200 Exporte_r.
global Database.QueryLocator start(Database.BatchableContext BC) {
String query = 'SELECT Id, Name, (SELECT Id FROM Exporte__r) FROM Portal__c';
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext BC, List<Portal__c> scope) {
for (Portal__c portal : scope) {
// doesn't work -> First error: Aggregate query has too many rows for direct assignment, use FOR loop
// when using FOR loop -> System.QueryException: invalid query locator
//List<Export__c> relatedExports = portal.Exporte__r;
// grab all the related Export__c records using 'getSObjects' to avoid errors described above
Export__c[] relatedExports = portal.getSObjects('Exporte__r');
if (relatedExports != null) {
for (Export__c exp : relatedExports) {
// do something
}
}
}
}
I have the following questions:
If I use List<Export__c> relatedExports = portal.Exporte__r (which I commented out) to get the sub query records then I will receive the error message: “Aggregate query has too many rows for direct assignment, use FOR loop”. The error message makes no sense for me as the SOQL is done already before. Is there any explaination?
With the solution above the maximal amount of records from type Exporte_r received per Portal_c with the sub query is 199 though I have more than 200 for some records of Portal__c, why is it limited to that number? It seems all records above 199 are ignored in this case.
Is there any possibility to receive more than 199 records from a sub query? I have tried to change the batch size but it seems it is independent of the number of records receivable by the sub query. Any idea?
Many thanks!
As per the salesforce doc http://www.salesforce.com/us/developer/docs/apexcode/Content/langCon_apex_loops_for_SOQL.htm
You might get a QueryException in a SOQLfor loop with the message
Aggregate query has too many rows for direct assignment, use FOR loop.
This exception is sometimes thrown when accessing a large set of child
records of a retrieved sObject inside the loop, or when getting the
size of such a record set. To avoid getting this exception, use a for
loop to iterate over the child records, as follows.
Integer count=0;
for (Contact c : returnedAccount.Contacts) {
count++;
// Do some other processing
}
I've an entity with assigned string Id on NHibernate and I've a little problem when get an entity by Id.
Example...
Suppose that have a database record like this...
Id Description
-------------------
AAA MyDescription
now, if I use "Get" method using search id "aaa"...
MYENTITYTYPE entity = Session.Get<MYENTITYTYPE>("aaa")
return right entity but Id field (entity.Id) is "aaa", while I wish it were equal to "AAA".
In summary I would like that "Get" method return the id identical to the one stored in the database...with the same case.
Is possible? How can I do?
Interesting question. My guess is that it's not possible, because the Id might exist before the DB call. Consider the following:
var foo = session.Load<Foo>("aaa"); //no DB call, foo is a proxy
Console.WriteLine(foo.Id); //Prints "aaa";
var bar = foo.Bar; //Forces loading
Console.WriteLine(foo.Id); //No matter what, the Id can't change at this point
This illustrates another reason why primary keys with meaning are usually a bad idea, especially if their input is not controlled.
Now, if instead of Get you use a query, you will get the right-cased Id:
//example with LINQ; you can use HQL, Criteria, etc
var foo = session.Query<Foo>().Single(x => x.Id == "aaa");
The drawback is that you will always go to the DB, even if the entity is already loaded.
Now, if you defined your entity as {Id, Code, Description}, where Id is a synthetic POID (I recommend Hilo or Guid) and Code is the existing string Id, you will avoid potential bugs caused by using Get instead of a query with the code.
I am using a recordstore to store some data,and each data is being shown in form of list elements.In my application,i am having a feature in which i can delete a particular list element.When i perform this action,item is getting deleted from the list but it is not working with the record.
I dont know why?
Can any one help me?
My code snippet is:
int x=list.getSelectedIndex();
list.delete(x);
try
{
rs_store.deleteRecord(x);
}
catch(Exception error)
{
System.out.print("error");
}
display.setCurrent(list);
Thanks in advance
If the indices of the items in your List are supposed to correspond with the indices of items in your RecordStore, then your problem may be down to the fact that RecordStore entries are 1-based, not 0-based.
So element 0 in your list will correspond to record 1 etc.