I have dynamic child objects in my JSON response to populate
preferences data, each preference can have "children" and that can
have multiple objects (in nested way, go into details). I need to save
this data into Core data then load from there. Also I need to save
user selection when user selects one on the way.
How to create tables which have parent child relationship? what is the
best way to implement entity relationship in entity model to save all
this data ? Here is my model classes:
class Menu: NSObject {
var active:String?
var code:String?
var desc:String?
var iconId:Int?
var inactive:String?
var isEatin:Int64?
var isTakeAway:Int64?
var menuId:Int?
var menuName:String?
var menuType:Int?
var parentId:Int?
var subMenus:[SubMenu]?
var products:[Product]?
}
class SubMenu: NSObject {
var code:String?
var desc:String?
var eatinPrice:Float?
var isEatin:Int?
var isTakeAway:Int?
var menuId:Int?
var menuName:String?
var menuType:Int?
var parentId:Int?
var sortOrder:Int?
var takeAwayPrice:Float?
var products:[Product]?
}
class Product: NSObject {
var addons:[Addon]?
var modifiers:[Modifier]?
var productImages:[ProductImages]?
var code:String?
var desc:String?
var eatinPrice:Float?
var isDisplayinMenu:Int?
var isEatin:Int?
var isProductset:Int?
var isTakeAway:Int?
var menuId:Int?
var name:String?
var note:String?
var printer:String?
var printerId:Int?
var printerType:String?
var productId:Int?
var rating:Int?
var sortOrder:Int?
var takeAwayPrice:Float?
}
class Addon: NSObject {
var addonsId:Int?
var addonsName:String?
var productId:Int?
var selectionCount:Int?
var addonTypes:[AddonType]?
}
class Modifier: NSObject {
var modifierId:Int?
var modifierName:String?
var productId:Int?
var modifierType:[ModifierType]?
}
class AddonType: NSObject {
var addonTypeId:Int?
var addonTypeName:String?
var price:Float?
var isAddonSelected:Int?
}
class ModifierType: NSObject {
var modifierTypeId:Int?
var modifierTypeName:String?
var isModifierSelected:Int?
}
class AddonModCombo: NSObject {
var addon:[Addon] = [Addon]()
var modifier:[Modifier] = [Modifier]()
var numberOfAddonMod = 1
}
To use Core Data you need to create a data model file-- roughly, a schema. Then your classes must inherit from NSManagedObject. Xcode can automatically create those subclasses for you based on the data model.
Relationships are configured in the data model, and represented as properties of the managed object classes. The result would be similar to your subMenus and products properties, but with a data model and with NSManagedObject.
Apple provides extensive, detailed documentation with sample code and screenshots. For example, relationships are described here: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/HowManagedObjectsarerelated.html#//apple_ref/doc/uid/TP40001075-CH17-SW1
Related
I am using node.js and n-api. The gist of it is that I cannot create a new object within a for loop without getting a type error that says:
TypeError: wrappedExamData.getPatientID is not a function
This only occurs when trying to create an object the second time. The first time works fine, though. If I create multiple new objects outside of the for loop, it works fine as well.
Here is the module that is throwing the error
//Require the node module
const nodeModule = require('../../../build/Release/QTWebUI.node');
//Require the Exam Class
const Exam = require('./Exam.js');
exports.retrieveAllExams = function(){
// Create a js wrapped c++ class to get a list of exam IDs
var msgGetExamList = new nodeModule.EMGetExamList_Wrapped();
// Create an array of the examIDs
var examList = msgGetExamList.getExamIDs();
console.log(examList);
var examArray = new Array();
for(let i = 0; i < examList.length; i++){
// Create a js wrapped c++ class to send get exam to scanner
var msgGetExam = new nodeModule.EMGetExam_Wrapped(examList[i]);
// Get the js wrapped examData from the c++ class
var wrappedExamData = msgGetExam.getWrappedExamData();
// Create a new exam object with the wrapped examData
var exam = new Exam(wrappedExamData);
// Print the newly created exam object
console.log("Exam: %s", JSON.stringify(exam));
// Push to array
examArray.push(exam);
}
return examArray;
};
Here is the Exam class that I am using where the error is traced back:
module.exports = internal.Exam = class{
constructor(wrappedExamData){
this.patientID = wrappedExamData.getPatientID();
this.firstName = wrappedExamData.getFirstName();
this.lastName = wrappedExamData.getLastName();
this.middleName = wrappedExamData.getMiddleName();
this.gender = wrappedExamData.getGender();
this.birthDate = wrappedExamData.getBirthDate();
this.scanTime = wrappedExamData.getScanTime();
this.description = wrappedExamData.getDescription();
this.breast = wrappedExamData.getBreast();
this.accession = wrappedExamData.getAccession();
this.operatorsName = wrappedExamData.getOperatorsName();
this.examState = wrappedExamData.getExamState();
this.progress = wrappedExamData.getProgress();
this.archiveMultiplicity = wrappedExamData.getArchiveMultiplicity();
this.density = wrappedExamData.getDensity();
this.targetType = wrappedExamData.getTargetType();
this.fromMWL = wrappedExamData.getFromMWL();
}
}
If I instantiate the objects like this:
// Create a js wrapped c++ class to send get exam to scanner
var msgGetExam = new nodeModule.EMGetExam_Wrapped(examList[0]);
// Get the js wrapped examData from the c++ class
var wrappedExamData = msgGetExam.getWrappedExamData();
// Create a new exam object with the wrapped examData
var exam = new Exam(wrappedExamData);
// Print the newly created exam object
console.log("Exam: %s", JSON.stringify(exam));
// Push to array
examArray.push(exam);
// Create a js wrapped c++ class to send get exam to scanner
var msgGetExam1 = new nodeModule.EMGetExam_Wrapped(examList[1]);
// Get the js wrapped examData from the c++ class
var wrappedExamData1 = msgGetExam1.getWrappedExamData();
// Create a new exam object with the wrapped examData
var exam1 = new Exam(wrappedExamData1);
// Print the newly created exam object
console.log("Exam: %s", JSON.stringify(exam1));
// Push to array
examArray.push(exam1);
It works fine. Is there something I'm missing here?
I am tryin to get some info from PeopleManager.getMyProperties() function.
I get the object,some values are null.when i check it from User Profile from Management,I can see the value. How can i fix this one ?
There is my working code to get object.
Note : I want to access Custom Property from User Profile which I created before.
I can see the property in the object but value is not coming.
Thank You All..
$(document).ready(function(){
SP.SOD.executeOrDelayUntilScriptLoaded(loadUserData, 'SP.UserProfiles.js');
});
var userProfileProperties;
function loadUserData(){
//Get Current Context
var clientContext = new SP.ClientContext.get_current();
//Get Instance of People Manager Class
var peopleManager = new SP.UserProfiles.PeopleManager(clientContext);
//Get properties of the current user
userProfileProperties = peopleManager.getMyProperties();
clientContext.load(userProfileProperties);
//Execute the Query.
clientContext.executeQueryAsync(onSuccess, onFail);
}
function onSuccess() {
console.log(userProfileProperties)
}
function onFail(sender, args) {
console.log("Error: " + args.get_message());
}
Try the below code and let me know. It works fine for me. I have passed the user name instead of My account. So that you can pass any user account here.
function getUserProperties(userName) {
var clientContext = new SP.ClientContext.get_current();
var peopleManager = new SP.UserProfiles.PeopleManager(clientContext);
var profilePropertyNames = ["FirstName", "LastName", "CustomProperty"]; //Have to load all the needed properties here
var targetUser = userName.trim();
var userProfilePropertiesForUser = new SP.UserProfiles.UserProfilePropertiesForUser(clientContext, targetUser, profilePropertyNames);
userProfileProperties = peopleManager.getUserProfilePropertiesFor(userProfilePropertiesForUser);
clientContext.load(userProfilePropertiesForUser);
clientContext.executeQueryAsync(onSuccess, onFail);
}
function onSuccess() {
// userProfileProperties result index is same as the properties loaded above
var firstName=userProfileProperties[0];
var lastName=userProfileProperties[1];
var customprop=userProfileProperties[2];
}
Mark it as answer if it helps.
I forget to write the solution,sorry for that one.
I tried the code which written by #NaveenPrasath. It is giving a lot of fields but it didn't return "Custom Prop Field".
Working code is shown below.
function getUserProperties(targetUser) {
var clientContext = new SP.ClientContext.get_current();
var peopleManager = new SP.UserProfiles.PeopleManager(clientContext);
personProperties = peopleManager.getPropertiesFor(targetUser);
clientContext.load(personProperties);
clientContext.executeQueryAsync(onRequestSuccess, onRequestFail);
}
function onRequestSuccess() {
var fullName = personProperties.get_userProfileProperties()['CustomPropField'];
}
Sorry, wasn't sure what exactly to search for as I'm sure this has been answered before but here goes. I have a webchat server using nodejs, I made a player class, but if I push the player class to the players array that contains all the users and update the player class such as player.id, the changes do not appear in the players array. How can I solve this?
var User = require('./User.js');
var wsID = 1; // should be random just for this example
var USERS = {};
USERS[wsID] = {
socket: "",
clientDetails: {
username: "",
isGuest: ""
}
}
user = new User();
user.setUsername("test");
USERS[wsID].username = user.getUsername; // works perfectly
user.setUsername("updatedit"); // fails to update array
console.log(USERS[wsID].username); // returns test and not updatedit...
class file:
var wsId,
socket,
username,
isGuest;
function User() {
}
User.prototype.getUsername = function(){
return this.username;
}
User.prototype.setUsername = function(name){
this.username = name;
}
module.exports = User;
You are missing the reference when you do this:
USERS[wsID].username = user.getUsername;
That's because you are cloning the current value of the property into another object. One way to solve this would be to change you code so you carry the instance "user" inside your "clientDetails" so it keeps updated:
user = new User();
user.setUsername("test");
USERS[wsID].clientDetails = user; // carry the entire instance
user.setUsername("updatedit");
console.log(USERS[wsID].clientDetails.username); // should return "updatedit"
While Strings appears to be fine I'm having some trouble storing Integers into Core Data. Following tutorials and reading available information out there doesn't seem to be helping me who has no Objective-C background. (Swift seemed like a straight forward language like the languages I'm fluent with PHP/OOPHP/JavaScript/VBScript/... thus I started playing with it and so far have been able to do everything I wanted, almost)
What I want to do now is, to receive the JSON data and store it into Core Data
Here's my Core Data
Entity name: Category
Its Attributes:
id Int16
title String
description String
My Swift model? file: Category.swift
import CoreData
class Category: NSManagedObject {
#NSManaged var id: Int //should I declare this as Int16?
#NSManaged var title: String
#NSManaged var description: String
}
I'm using SwiftyJASON extension? and NSURLSession protocol? to get the data and to parse it as follow:
import UIKit
import CoreData
class ViewController: UIViewController {
let managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext
override func viewDidLoad() {
super.viewDidLoad()
fetchData()
}
func fetchData() {
var url = NSURL.URLWithString("http://domain.com/index.php?r=appsync/read&id=category")
var session = NSURLSession.sharedSession()
session.dataTaskWithURL(url, completionHandler: {(data, response, error) in
// parse data into json
let json = JSONValue(data)
let entityDescription = NSEntityDescription.entityForName("Category", inManagedObjectContext: self.managedObjectContext)
let category = Category(entity: entityDescription, insertIntoManagedObjectContext: self.managedObjectContext)
for item in json.array! {
category.id = item["id"].string!.toInt()! //goes KABOOM!
category.title = item["title"].string!
category.description = item["description"].string!
managedObjectContext?.save(nil)
}
dispatch_async(dispatch_get_main_queue()) {
// do something
}
}).resume()
}
}
Let's assume the JASON data is:
[{"id":"1","title":"cat1","description":"blabala one"},{"id":"2","title":"cat2","description":"blabala two"}]
At line where it says category.id = item["id"].string!.toInt()! xCode goes KABOOM, what am I doing wrong here?
Notes/More questions:
I tried changing id type within Core Data to Int32 and then declaring it as just Int
in the model (and not Int16 or Int32) which reduced some errors but
xCode still crashes
Probably the way I'm looping stuff is not the best way to do this,
what's the better way of storing array of data into core data at
once?
Most of the tutorials I've seen there's no id's for Entities(tables), am I missing something here?
References:
SiftyJSON: https://github.com/lingoer/SwiftyJSON
Core Data tutorial:
http://rshankar.com/coredata-tutoiral-in-swift-using-nsfetchedresultcontroller/
EDIT > Working code:
Category.swift model file which can be auto generated using File>New>File>iOS>Core Data>NSManagedObject subclass [swift, no need for bridging header but you need to manually add #objc line as below]
import CoreData
#objc(Category) //Wouldn't work without this
class Category: NSManagedObject {
#NSManaged var id: NSNumber //has to be NSNumber
#NSManaged var title: String
#NSManaged var mydescription: String //"description" is reserved so is "class"
}
ViewController.swift
import UIKit
import CoreData
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
fetchData()
}
func fetchData() {
var url = NSURL.URLWithString("http://domain.com/index.php?r=appsync/read&id=category")
var session = NSURLSession.sharedSession()
session.dataTaskWithURL(url, completionHandler: {(data, response, error) in
let json = JSONValue(data)
let managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext //this line had to be moved here
let entityDescription = NSEntityDescription.entityForName("Category", inManagedObjectContext: managedObjectContext)
for item in json.array! {
let category = Category(entity: entityDescription, insertIntoManagedObjectContext: managedObjectContext) //this line has to be in inside for loop
category.id = item["id"].string!.toInt()!
category.title = item["title"].string!
category.mydescription = item["description"].string!
managedObjectContext?.save(nil)
}
dispatch_async(dispatch_get_main_queue()) {
// do something
}
}).resume()
}
}
Sample fetching data code:
func requestData() {
let appDel:AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let context:NSManagedObjectContext = appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "Category")
request.returnsObjectsAsFaults = false
var results:NSArray = context.executeFetchRequest(request, error: nil)
//println(results)
for category in results {
var cat = category as Category
println("\(cat.id),\(cat.title),\(cat.mydescription)")
}
}
P.S. Make sure to Clean your project and delete the app from simulator after changing Model
Scalar types (integers, floats, booleans) in core data are broken in the current Swift beta (5). Use NSNumber for the properties, and file a radar.
object.intProperty = NSNumber(int:Int(item["id"] as String))
(Typed on the phone, so sorry if that's wrong, and I know it's disgusting code - hence, file a radar!)
Or, in your specific case, looking at the JSON, use String. Those IDs are coming in as strings anyway.
Updated for Swift 2
If your JSON data is really of type [[String:String]], you can use the following code in order to set category.id:
if let unwrappedString = item["id"], unwrappedInt = Int(unwrappedString) {
category.id = unwrappedInt
}
I want to post some request values alongside the multipart-formdata file contents. In the old API you could use PostFileWithRequest:
[Test]
public void Can_POST_upload_file_using_ServiceClient_with_request()
{
IServiceClient client = new JsonServiceClient(ListeningOn);
var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPath());
var request = new FileUpload{CustomerId = 123, CustomerName = "Foo"};
var response = client.PostFileWithRequest<FileUploadResponse>(ListeningOn + "/fileuploads", uploadFile, request);
var expectedContents = new StreamReader(uploadFile.OpenRead()).ReadToEnd();
Assert.That(response.FileName, Is.EqualTo(uploadFile.Name));
Assert.That(response.ContentLength, Is.EqualTo(uploadFile.Length));
Assert.That(response.Contents, Is.EqualTo(expectedContents));
Assert.That(response.CustomerName, Is.EqualTo("Foo"));
Assert.That(response.CustomerId, Is.EqualTo(123));
}
I can't find any such method in the new API, nor any overrides on client.Post() which suggest that this is still possible. Does anyone know if this is a feature that was dropped?
Update
As #Mythz points out, the feature wasn't dropped. I had made the mistake of not casting the client:
private IRestClient CreateRestClient()
{
return new JsonServiceClient(WebServiceHostUrl);
}
[Test]
public void Can_WebRequest_POST_upload_binary_file_to_save_new_file()
{
var restClient = (JsonServiceClient)CreateRestClient(); // this cast was missing
var fileToUpload = new FileInfo(#"D:/test/test.avi");
var beforeHash = this.Hash(fileToUpload);
var response = restClient.PostFileWithRequest<FilesResponse>("files/UploadedFiles/", fileToUpload, new TestRequest() { Echo = "Test"});
var uploadedFile = new FileInfo(FilesRootDir + "UploadedFiles/test.avi");
var afterHash = this.Hash(uploadedFile);
Assert.That(beforeHas, Is.EqualTo(afterHash));
}
private string Hash(FileInfo file)
{
using (var md5 = MD5.Create())
{
using (var stream = file.OpenRead())
{
var bytes = md5.ComputeHash(stream);
return BitConverter.ToString(md5.ComputeHash(stream)).Replace("-", "").ToLower();
}
}
}
None of the old API was removed from the C# Service Clients, only new API's were added.
The way you process an uploaded file inside a service also hasn't changed.