Delete data from FMDB using an array in swift - swift

I am trying to delete multiple rows from database. Currently, I have an array which consists of all the row id's which i want to delete. But i cannot seem to find a suitable code for it
func deleteMultiple(Id:[Int]) -> NSMutableArray {
sharedInstance.databese!.open()
var i:Int = Id.count
print(Id, i)
let resultSet:FMResultSet! = sharedInstance.databese!.executeQuery("DELETE FROM Info WHERE Id = ?", withArgumentsIn: Id)
let itemInfo:NSMutableArray = NSMutableArray ()
if (resultSet != nil)
{
while resultSet.next() {
let item:Tbl_Info = Tbl_Info()
item.Id = Int(resultSet.int(forColumn: "Id"))
item.Name = String(resultSet.string(forColumn: "Name")!)
item.LastName = String(resultSet.string(forColumn: "LastName")!)
itemInfo.add(item)
}
}
sharedInstance.databese!.close()
return itemInfo
}

You can execute your query in a queue it will not freeze your database.
if anything fails during the transaction FMDB Provides the rollback functionality.
Look at the sample code.
sharedInstance.databese.dbQueue.inTransaction { db, rollback in
idArray.forEach {id in
do {
let resultSet:FMResultSet! = try db.executeQuery("DELETE FROM Info WHERE Id = ?", withArgumentsIn: Id)
//Do whatever with your resultSet
} catch {
//Error occured during deleting from database.
rollback.pointee = true
}
}
}

Related

Coredata update/insert for one to many relationship

I have a one to many relationship in my coredata object graph, typically User<->>Device. Lets say from my API i get a response of something as bellow
[
{
user:"John"
id:1
devices:[
{
id:1
name:"iPhoneX"
},
{
id:2
name:"Samsung Galaxy Plus"
}
]
},
{
user:"Peter"
id:"2"
devices:[
{
id:3
name:"iPhone5s"
},
{
id:4
name:"Samsung Galaxy"
}
]
}
]
Now the objective is to do a simple update/insert to my coredata tables. My Partial code as bellow for updating and inserting Device table
func updateDevice (userID:String, apiDevicesArray:[APIResposeDevice]){
for device in apiDevicesArray {
let request:NSFetchRequest<Device> = Device.fetchRequest()
request.predicate = NSPredicate(format:"id = %#", device.id)
do{
let searchResults = try self.privateMOC.fetch(request)
if searchResults.count > 0 {
//Update
let update_device = searchResults.last
update_device.name = device.name
update_device.id = device.id
}else{
//Stuck with inserting a device to the proper user
request.predicate = NSPredicate(format: "owner.id = %#, userID)
do{
let devicesArrayForUserID = try self.privateMOC.fetch(request)
//How to insert a record to this array now ???
}catch{
}
}
}catch{
}
}
}
First, you need to fetch the User.
Then, you have to choices:
user.devices.add(device)
or if it's two ways relationship, then you can call device.user = user

Trying to Move Cards

I am trying to move a card I have found using the search function from one list to another on the same board.
I have tried to set up a new list using the a new factory.list and searching for the list using FirstorDefault LINQ Query but keep getting an Error.
Below is some code I have tried to move my cards.
string query = jnum;
var search = factory.Search(query, 1, SearchModelType.Cards, new IQueryable[] { board });
await search.Refresh();
var CardList = search.Cards.ToList();
foreach (var card in CardList)
{
string tName = card.Name.Substring(0, 6);
if (tName == jnum.Trim())
{
cardid = card.Id;
}
}
var FoundCard = factory.Card(cardid);
string FoundListid = FoundCard.List.Id;
var fromlist = factory.List(FoundListid);
if (Item != null)
{
if (mail.Body.ToUpper().Contains("Approved for Print".ToUpper()))
{
//var ToList = factory.List("5db19603e4428377d77963b4");
var ToList = board.Lists.FirstOrDefault(l => l.Name == "Signed Off");
FoundCard.List = ToList;
// from on proof
//MessageBox.Show("Approved for Print");
}
else if (mail.Body.ToUpper().Contains("Awaiting Review".ToUpper()))
{
//var ToList = factory.List("5db19603e4428377d77963b3");
var ToList = board.Lists.FirstOrDefault(l => l.Name == "On Proof");
FoundCard.List = ToList;
// from in progress or to start
// MessageBox.Show("Awaiting Review");
}
else if (mail.Body.ToUpper().Contains("Amends".ToUpper()))
{
var ToList = factory.List("5dc9442eb245e60a39b3d4a7");
FoundCard.List = ToList;
// from on proof
//MessageBox.Show("Amends");
}
else
{
// non job mail
}
}
I keep getting a is not a valid value Error.
Thanks for help

Swift iOS application not saving all object Parse

My problem is adding new numbers to the array field in users. all the code seems to work but i have the problem with saveAll function. All the names are correct, as i've checked on several different occasions.
func taskAllocation(){
var query = PFUser.query()
var objectQuery:[PFUser] = [PFUser]()
query.whereKey("Year", equalTo: yearTextField.text.toInt())
query.whereKey("Class", equalTo: classTextField.text.toInt())
query.whereKey("Keystage", equalTo: keystageTextField.text.toInt())
query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]!, error: NSError!) -> Void in
if error != nil {
println(error)
} else {
if objects.isEmpty {
println("empty query")
}
else {
for object in objects as [PFUser] {
var test:[Int] = object["taskIDs"] as [Int]
test.append(self.getIndex)
println(test)
object["taskIDs"] = test
object["tasksCompleted"] = "hello"
objectQuery.append(object)
}//For
println(objectQuery.count)
if objectQuery.count != 0{
println("Success!!!")
println(objectQuery)
PFUser.saveAllInBackground(objectQuery)
}
}
}
}
This below is stored in the println(objectQuery) as you can see the taskIDs have been appended and the tasksCompleted contains the string. Which leads me to believe that there is a problem with the saveallinbackground function.
[<PFUser: 0x155f6510, objectId: W6TrPQwCQ7, localId: (null)> {
Class = 2;
Forename = "Joe ";
Keystage = 2;
Surname = Freeston;
Year = 4;
admin = false;
completedTaskIDs = (
);
taskIDs = (
0,
2,
4,
5,
6,
46
);
tasksCompleted = hello;
tasksCorrect = 0;
userType = Student;
username = jfreeston;
}, <PFUser: 0x1569b7a0, objectId: slLd1KBIaM, localId: (null)> {
Class = 2;
Forename = "Camilla ";
Keystage = 2;
Surname = Linhart;
Year = 4;
admin = false;
completedTaskIDs = (
);
taskIDs = (
0,
46
);
tasksCompleted = hello;
tasksCorrect = 0;
userType = Student;
username = clinhart;
}]
Not sure if anyone has more knowledge of the parse api, mainly how the saveall/saveallinbackground functions work maybe.
To save all in background as a user I would first create a PFUser variable, like
var NewUser = PFUser.currentUser
Then to save in background
newUser.saveInBackgroundWithBlock {
(success:Bool, error: NSError!) -> Void in {
}
Then you can put if-statements and stuff within those brackets to do what you need it to when successful. like:
if(success) {
performSegueWithIdentifier("YourSegue", sender: nil)
}

Entity Framework savechanges() update delete insert

I want my SaveChanges() function to update a record in my database and if the return value is '1' which is coming from my stored procedure then and only then 'delete' command (stored procedure) should not be executed.
Now, the problem is db.SaveChanges() (an instance of ObjectContext) is updating my record successfully but after updating, it executes the delete command. How should I tell my function that not to execute delete command.
using (var db = new PRLAdminEntities())
{
bool isExists = false;
string lastExisting = string.Empty;
string errorString = string.Empty;
db.Connection.Open();
trans = db.Connection.BeginTransaction();
//accounts to be sent back to client
var countriesToSendBack = new List<Polo.Common.Shared.Entities.Country>();
//process each account requiring database update
if (request.CountriesToUpdate != null)
{
foreach (var country in request.CountriesToUpdate)
{
//countriesToSendBack.Remove(country);
var temp = from row in db.Countries where row.Name.ToUpper() == country.Name.ToUpper() select row;
if (temp.Count<Polo.Common.Shared.Entities.Country>() > 0 && country.ChangeTracker.State == ObjectState.Added)
{
countriesToSendBack.Add(country);
db.Countries.ApplyChanges(country);
isExists = true;
lastExisting = country.Name;
errorString += country.Name + ", ";
//db.GetAllCountries();
//break;
continue;
}
if (country.ChangeTracker.State == ObjectState.Deleted)
{
db.DeleteObject(country);
}
//if a change or modification (not a delete)
if (country.ChangeTracker.State != ObjectState.Deleted)
{
//this account should be sent back
if (!countriesToSendBack.Contains((country)))
countriesToSendBack.Add(country);
if (country.Active == false)
{
db.Countries.ApplyCurrentValues(country);
}
}
//apply all changes
db.Countries.ApplyChanges(country);
}
if (isExists)
{
//response.Success = false;
//errorString.Replace(", " + lastExisting + ",", " & " + lastExisting);
//response.FaultMessage = "Duplicate Records";
}
}
//save all changes
int total = db.SaveChanges();
response.Success = true;
foreach (var countryItem in countriesToSendBack)
{
countryItem.Id = (from row in db.Countries where row.Name.ToUpper() == countryItem.Name.ToUpper() select row.Id).FirstOrDefault();
}
trans.Commit();
//refresh the account data which gets timestamp etc
db.Refresh(RefreshMode.StoreWins,countriesToSendBack);
//set the response values
response.Countries = countriesToSendBack;
}
}
Perhaps I misread your question, I do not totally get what you are trying to do.
But why not call SaveChanges() after the change and when all checks are positive perform a remove() and call savechanges() again?
There is no harm is calling SaveChanges() multiple times. It will mirror it's data to your database. If you perform a remove it will try to delete it in your database. That's the nice thing about it.. it does what you tell it to do ;-)

How to get the PFRelation objects while getting the PFquery objects?

NSPredicate *predicate=[NSPredicate predicateWithFormat:#"(UserId==%#)",[defaluts objectForKey:#"objectId"]];
PFQuery *frndquery=[PFQuery queryWithClassName:#"FriendsDetails" predicate:predicate];
[frndquery orderByDescending:#"lastdate"];
[frndquery whereKey:#"BlockStatus" equalTo:#"No"];
NSArray *arrquery=[frndquery findObjects];
for (PFObject *frndids in arr){
PFRelation *relation=[frndids relationforKey:#"ChatRelation"];
NSArray *arrids=[NSArray arrayWithObjects:[frndids objectForKey:#"UserId"],[frndids objectForKey:#"ConversationID"], nil];
PFQuery *statusQuery = [relation query];
[statusQuery orderByDescending:#"createdAt"];
[statusQuery whereKey:#"Deletechat" notContainedIn:arrids];
statusQuery.limit = [[NSNumber numberWithInt:1] intValue];
NSArray *arrforrelationobjects=[statusQuery findObjects];}
I want to find all objects when we retrieve the objects from the first query itself. Please solve my problem
There is a method you can use to include properties which are pointer values. You cannot use the include method with relations. What I do instead is use a Cloud Code function to aggregate the results I want into a JSON object and return that object.
See the fetchPostDetails function in the following script.
https://github.com/brennanMKE/PostThings/blob/master/Parse/PostThings/cloud/main.js
It fetches items are relation objects such as tags and likes which happen to be User objects which are relations to the Post class. There are also comments which are referenced as a pointer back to the post from each comment. The fetchPostTags and fetchPostLikes methods show how to fetch those relations and populate the JSON object which is holding all of the results. You need to deploy those Cloud Code update and then access it as a function from the iOS side. The results will come back as an NSDictionary with values for posts, tags, likes and comments. The posts are an array of Post objects. The tags, likes and comments are NSDictionary objects which have the postId as the key to access the array of Parse objects.
This way one call to the function will get you want you need.
I've included some of the code below as a reference in case what is on GitHub changes.
// Helper functions in PT namespace
var PT = {
eachItem : function (items, callback) {
var index = 0;
var promise = new Parse.Promise();
var continueWhile = function(nextItemFunction, asyncFunction) {
var item = nextItemFunction();
if (item) {
asyncFunction(item).then(function() {
continueWhile(nextItemFunction, asyncFunction);
});
}
else {
promise.resolve();
}
};
var nextItem = function() {
if (index < items.length) {
var item = items[index];
index++;
return item;
}
else {
return null;
}
};
continueWhile(nextItem, callback);
return promise;
},
arrayContainsItem : function(array, item) {
// True if item is in array
var i = array.length;
while (i--) {
if (array[i] === item) {
return true;
}
}
return false;
},
arrayContainsOtherArray : function(array, otherArray) {
/// True if each item in other array is in array
var i = otherArray.length;
while (i--) {
if (!PT.arrayContainsItem(array, otherArray[i])) {
return false;
}
}
return true;
},
fetchPostTags : function(post) {
return post.relation("tags").query().find();
},
fetchPostLikes : function(post) {
return post.relation("likes").query().find();
},
fetchPostComments : function(post) {
var query = new Parse.Query(Comment);
query.include("owner");
query.equalTo("post", post);
return query.find();
},
fetchPostDetails : function(post, json) {
json.tags[post.id] = [];
json.likes[post.id] = [];
json.comments[post.id] = [];
return PT.fetchPostTags(post).then(function(tags) {
json.tags[post.id] = tags;
return PT.fetchPostLikes(post);
}).then(function(likes) {
json.likes[post.id] = likes;
return PT.fetchPostComments(post);
}).then(function(comments) {
json.comments[post.id] = comments;
json.count++;
return Parse.Promise.as();
});
},
};