How to change the value of a certain core data across VCs/ How to know the index of a created CoreData? - core-data

I start from a TableView to create and store user information. This is how I create a core data entity called "Trials" in CreateTrialViewController. And I can successfully fetch it in the tableViewController after I come back to it.
let trial : Trials = NSEntityDescription.insertNewObjectForEntityForName("Trials", inManagedObjectContext: self.managedObjectContext!) as? Trials
{
trial.project = theProject.text
trial.record = theRecord.text
trial.notes = theNotes.text
trial.percentile = ""
managedObjectContext?.save(nil)
}
'
But after I create the Trial, I will get some calculated results from the accelerometer in the next measureViewController, and I want to save the result into 'trial.percentile'.
I have already converted the results into a string, so I can write it directly into the core data attribute. But how can I know the index of this core data that I just created? Should I try to use 'segue' to transmit?
In the tableView it fetches in a ascending sequence of date, so the index is clear. But here in the following VC how to know the index? I still couldn't figure this out by myself... The sequence of my VCs is: TableViewController -> CreateTrialViewController -> MeasureViewController -> TableViewController (start again)

Your table view controller can keep a reference to the newly created object. Insert the object (trial) in the original view controller and pass it on to the next controller in prepareForSegue. So the CreateTrialViewController starts out with a blank object to which the table view controller has a reference.
You configure the object, go to the measure controller, modify the object. When done, you pop these two controllers from the navigation stack and are back in your original table view controller.
Because your table view controller has the NSFetchedResultsControllerDelegate enabled, it will update itself to reflect the data of your new object. Remember, you still have a reference to this object, so you can just use indexPathForObject to retrieve its index path.

Related

Android Studio Room query to get a random row of db and saving the rows 2nd column in variable

like the title mentions I want a Query that gets a random row of the existing database. After that I want to save the data which is in a specific column of that row in a variable for further purposes.
The query I have at the moment is as follows:
#Query("SELECT * FROM data_table ORDER BY RANDOM() LIMIT 1")
fun getRandomRow()
For now I am not sure if this query even works, but how would I go about writing my function to pass a specific column of that randomly selected row to a variable?
Ty for your advice, tips and/or solutions!
Your query is almost correct; however, you should specify a return type in the function signature. For example, if the records in the data_table table are mapped using a data class called DataEntry, then the query could read as shown below (note I've also added the suspend modifier so the query must be run using a coroutine):
#Query("SELECT * FROM data_table ORDER BY RANDOM() LIMIT 1")
suspend fun getRandomRow(): DataEntry?
If your application interacts with the database via a repository and view model (as described here: https://developer.android.com/topic/libraries/architecture/livedata) then the relevant methods would be along the lines of:
DataRepository
suspend fun findRandomEntry(): DataEntry? = dataEntryDao.getRandomRow()
DataViewModel
fun getRandomRecord() = viewModelScope.launch(Dispatchers.IO) {
val entry: DataEntry? = dataRepository.findRandomEntry()
entry?.let {
// You could assign a field of the DataEntry record to a variable here
// e.g. val name = entry.name
}
}
The above code uses the view model's coroutine scope to query the database via the repository and retrieve a random DataEntry record. Providing the returning DataEntry record is not null (i.e. your database contains data) then you could assign the fields of the DataEntry object to variables in the let block of the getRandomRecord() method.
As a final point, if it's only one field that you need, you could specify this in the database query. For example, imagine the DataEntry data class has a String field called name. You could retrieve this bit of information only and ignore the other fields by restructuring your query as follows:
#Query("SELECT name FROM data_table ORDER BY RANDOM() LIMIT 1")
suspend fun getRandomRow(): String?
If you go for the above option, remember to refactor your repository and view model to expect a String instead of a DataEntry object.

Reading integer from Core Data

In my app I have a Core Data entity called Status with two attributes messageID as Integer32 and messageText as String.
I have a string stored in an SQL database which the app downloads on startup. The string from the database is broken down into two parts ID and text. An example message could be 011-Hello and the each part is stored in an array called messageParts. The first item in the array is the ID:
NSInteger newMessageID = [messageParts[0] integerValue];
I want to compare this ID with the one stored in Core Data such as:
if (messageID == newMessageID)
I get the newMessageID fine and I have a number to work with but I am totally confused as to how to handle the data type coming from Core Data. I can see that there is a number in the database using SQLlitebrowser and I have tried:
NSInteger *savedMessageID = [[self.status objectAtIndex:0] messageID];
and
NSInteger savedMessageID = [[self.status objectAtIndex:0] messageID];
But neither return the stored value. I think that this is a pointer issue but I am going around in circles here.
If you generate the NSManagedObject subclass from your xcdatamodeld (Xcode menu Editor > Create NSManagedObject Subclass…), you will find that the integer32 field is generated as an NSNumber...
This is maybe where you should take a look ?

Can't set Orchard field values unless item already created

I seem to be having a problem with assigning values to fields of a content item with a custom content part and the values not persisting.
I have to create the content item (OrchardServices.ContentManager.Create) first before calling the following code which modifies a field value:
var fields = contentItem.As<MyPart>().Fields;
var imageField = fields.FirstOrDefault(o => o.Name.Equals("Image"));
if (imageField != null)
{
((MediaLibraryPickerField)imageField).Ids = new int[] { imageId };
}
The above code works perfectly when against an item that already exists, but the imageId value is lost if this is done before creating it.
Please note, this is not exclusive to MediaLibraryPickerFields.
I noticed that other people have reported this aswell:
https://orchard.codeplex.com/workitem/18412
Is it simply the case that an item must be created prior to amending it's value field?
This would be a shame, as I'm assigning this fields as part of a large import process and would inhibit performance to create it and then modify the item only to update it again.
As the comments on this issue explain, you do need to call Create. I'm not sure I understand why you think that is an issue however.

Passing data in a pop/back event to a previous view model

I have a structure like so :
SessionsView -> CreateSessionView
with view models like so :
SessionsViewModel - List of Session objects
CreateSessionViewModel - Single Session Object
The user fills in a form in create session, populates the Session object on the view model, hits done and I call : NavigationController.PopViewControllerAnimated(true) to take them back to the list of sessions.
Is there a way of passing my newly created session object back to the previous views Viewmodel and adding it to its list of session objects? I know how to pass params in a ShowViewModel<TYPE>(PARAM) command, but not sure how to do it whilst navigating back.
Update 1 :
I found 'a' way to do it.. doesn't feel too nice though :
var sessionsView = (SessionsView)NavigationController.ViewControllers.FirstOrDefault(vc => vc is SessionsView);
var sessionsViewModel = (SessionsViewModel)sessionsView.ViewModel;
sessionsViewModel.Sessions.Add(vModel.Session);
NavigationController.PopViewControllerAnimated(true);
Just make use of the return parameter of PopViewControllerAnimated(bool animated).
NavigationController.PopViewControllerAnimated(true);
ViewControllerClass viewController = (ViewControllerClass)NavigationController.TopViewController;
viewController.StoreSessionObject(session); <-- you need to create this method

How to assign a value to an Orchard ContentPickerField from code?

I am working on an Orchard site that needs to be able to use some customized forms to create new content items.
To handle this I'm using a controller to display a form and then trying to create the new content items on post back by populating the dynamic items and then sending them through the ContentManagerService's Create() function.
This is working ok until I got to the content picker field I have as part of my content item.
In my project I have a content type of Question Record that has a SubmittedBy field that is a Content Picker Field.
Here is what I can see in the immediate window while processing the post back:
> dynamic q = _questionService.NewQuestion("Why doesn't this work?");
{Custom.Website.Models.Question}
base {Orchard.ContentManagement.ContentPart}: {Custom.Website.Models.Question}
IsNew: true
OriginalQuestion: "Why doesn't this work?"
Summary: null
> q.QuestionRecord
{Orchard.ContentManagement.ContentPart}
base {System.Dynamic.DynamicObject}: {Orchard.ContentManagement.ContentPart}
ContentItem: {Orchard.ContentManagement.ContentItem}
Fields: Count = 5
Id: 0
PartDefinition: {Orchard.ContentManagement.MetaData.Models.ContentPartDefinition}
Settings: Count = 0
TypeDefinition: {Orchard.ContentManagement.MetaData.Models.ContentTypeDefinition}
TypePartDefinition: {Orchard.ContentManagement.MetaData.Models.ContentTypePartDefinition}
Zones: {Orchard.UI.ZoneCollection}
> q.QuestionRecord.SubmittedBy
{Orchard.ContentPicker.Fields.ContentPickerField}
base {Orchard.ContentManagement.ContentField}: {Orchard.ContentPicker.Fields.ContentPickerField}
ContentItems: null
Ids: {int[0]}
The ContentItems property is read-only and the Ids when assigning a new int[] to the Ids array I get a System.ObjectDisposedException with the message: Instances cannot be resolved and nested lifetimes cannot be created from this LifetimeScope as it has already been disposed.
Are there any workarounds to get this value set in code or do I need to create my own property to store the related content item ids? It would be very helpful to have the admin interface of the ContentPickerField also available.
Thanks.
If you have a reference to the ContentPickerField, you can assign it a value using the Ids property.
In example (assuming your content type has a part called Question which has a field called SubmittedBy):
var submittedByField = ((dynamic)q.ContentItem).Question.SubmittedBy;
sbmittedByField.Ids = new[] { submittedById };
As Bertrand mentioned, the format to access a content field is: contentItem.PartName.FieldName.
If you attached a field to a type directly via the admin, the part name has the same name as the type name, hence contentItem.TypeName.FieldName (where TypeName is actually the name of the implicitly created part).

Resources