Core Data uniqueness - core-data

Is there any way I can validate a value updated in a Core Data entity's property against values of the property in other entities in the collection?
At the moment I create an entity with some default values, add it to arrangedObjects, then get the user to modify the various property values. However, I would like to check a particular property and make sure there're no other entities in the array with the same value for that property. What's the best way to do this?
Many thanks,
Dany.

Manually checking is only a few lines of code with a fast enumeration loop:
BOOL unique = YES;
for (NSManagedObject *obj in collection) {
if (obj.property == value) {
unique = NO;
break;
}
}

Related

How to clear the contents of all the attributes of an entity?

I have data recorded in the attributes of a entities in coredata.
I would like to erase the data saved in each attribute of an entity.
Please is there a way to do it and if so, how?
Thank you
Get the NSEntityDescription of that object (that's the entity property of the NSManagedObject).
And then you can simply iterate on the names (via the attributesByName property) and set all values to nil
for (name, attributes) in entity.attributesByName { setValue(nil, forKey: name) }
You can do the same for the relationships of that object (via the relationshipsByName property)
for (name, relationship) in entity.relationshipsByName { setValue(nil, forKey: name) }
With this methods you can also exclude specific properties (if there are some you don't want to clear).

How can I ensure CassandraOperations.selectOneById() initializes all fields in the POJO?

I'm using Spring Data Cassandra 1.3.4.RELEASE to persist instances of a class that I have. The class is written in Groovy, but I don't think that really matters. I have implemented a CrudRepository, and I'm injecting an instance of CassandraOperations into the repo implementation class. I can insert, delete, and do most of the other operations successfully. However, there's a scenario I'm running into which breaks my test case. My entity class looks something like this:
#Table("foo")
class FooData {
#PrimaryKey("id")
long id
#Column("created")
long updated
#Column("name")
String name
#Column("user_data")
String userData
#Column("numbers")
List numberList = []
}
In my test case, I happened to only set a few fields like 'id' and 'updated' before calling CassandraOperations.insert(entity), so most of them were null in the entity instance at the time of insertion. But the numberList field was not null, it was an empty List. Directly after the insert(), I'm calling CassandraOperations.selectOneById(FooData.class, id). I get a FooData instance back, and the fields that were initialized when I saved it are populated with data. However, I was checking content equality in my test, and it failed because the empty list was not returned as an empty list in the POJO coming back from CassandraOperations.selectOneById(). It's actually null. I assume this may be some sort of Cassandra optimization. It seems to happen in the CGLIB code that instantiates the POJO/entity. Is this a known "feature"? Is there some annotation I can mark the 'numberList' field with to indicate that it cannot be null? Any leads are appreciated. Thanks.
In short
Cassandra stores empty collections as null and Spring Data Cassandra overwrites initialized fields.
Explanation
Cassandra list/set typed columns represent an empty collection as null. It does not matter whether the list/set (as viewed from Java/Groovy) was empty or null. Storing an empty list yields therefore in null. From here one can't tell whether the state was null or empty at the time saving the value.
Spring Data Cassandra overwrites all fields with values retrieved from the result set and so your pre-initialized fields is set to null.
I created a ticket DATACASS-266 to track the state of this issue.
Workaround
Spring Data uses setters if possible so you have a chance to intervene. A very simple null guard could be:
public void setMyList(List<Long> myList) {
if(myList == null){
this.myList = new ArrayList<>();
return;
}
this.myList = myList;
}
As important addition to mp911de answer you have to set #org.springframework.data.annotation.AccessType(AccessType.Type.PROPERTY) to make this solution work.

Core Data NSFetchRequest Sort by Category Method Return Value

How do I sort my fetched results by a value that is returned by a method in a category of the entity I'm fetching?
In my category, I sum up several values from the entity's to-many relationship, then divide by the number of objects in the relationship, effectively creating an average that I return in my category method as a float value.
Here is my code:
In the Category.h
- (float)smallPenaltyAvg;
In the Category.m
- (float)smallPenaltyAvg{
float smallPenaltyAvg = 0;
for (Match *mtch in self.matches) {
smallPenaltyAvg += [mtch.penaltySmall floatValue];
}
if ([self.matches count] > 0) {
smallPenaltyAvg = (float)smallPenaltyAvg/(float)[self.matches count];
}
return smallPenaltyAvg;
}
And when I call it in the Core Data Table View Controller class that I created...
NSFetchRequest *poolRequest = [[NSFetchRequest alloc] initWithEntityName:#"Team"];
poolRequest.predicate = [NSPredicate predicateWithFormat:#"regionalIn.name = %#", _regionalToDisplay];
poolRequest.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"smallPenaltyAvg" ascending:YES]];
And I have the Category.h file imported on every file previously mentioned outside of the Category.h file itself.
It gives me the error of:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'keypath smallPenaltyAvg not found in entity <NSSQLEntity Team id=5>
Am I not allowed to do this?
If I am, what am I doing wrong?
I do not think this has anything to do with the kind of persistent store.
The trick is to create an appropriate attribute in the managed object model, and mark it as Transient. Then override the getter of this attribute to do your calculations.
Now your fetch request should work as expected (although there are some caveats with fetched results controllers).
As for the SQLite problem, when you add the SQLite store with
- (NSPersistentStore *)addPersistentStoreWithType:(NSString *)storeType
configuration:(NSString *)configuration
URL:(NSURL *)storeURL
options:(NSDictionary *)options
error:(NSError **)error
just pass NSSQLiteStoreType as the storeType. The other options are binary and in-memory, so in this sense this is indeed the "default".
This is not possible when using a backing SQLite store.
My suggestion is you persist the average property, and maintain it yourself by overriding the Match setCategory: property and making the calculation there for every match added.
What I did to solve my problem was create a new attribute for every average or sum that I needed in the Team object from all of its Match objects' attributes and then created a method in the TeamCategory file that populated those averages and that method was called every time a Match object was inserted into the Team object. It took a while to do, but it works now. If there is a better solution, I'm still open for suggestions.

What is the correct way for quering a NSNumber in a NSArray within CoreData?

I have a Entity with a column of type ID named "responsibleUsers". In this column I store an Array containing NSNumbers.
I want to fetch all objects of this entity, that match my current User. Therefore i create following predicate:
[NSPredicate predicateWithFormat: #"%# IN responsibleUsers",[NSNumber numberWithInteger: curUser.oID.integerValue] ]
whatever I try, my App crashes. Once with a EXC_BAD_ACESS, once with "unimplemented SQL generation for predicate nsnumber"
What is the correct way to query my entity?
The query you are trying assumes that you have two entities: the entity you querying (let's call it Group) and another one, perhaps called User, which is set up as a to-many relationship from Group called responsibleUsers. You would then be able to use the predicate you suggest:
[NSPredicate predicateWithFormat:#"%# IN responsibleUsers, aUser];
This would be the recommended use of Core Data object graphs.
In your setup, it seems you have an array of NSNumber set as a property rather than a relationship. Therefore you cannot use such a query. You simply have to retrieve the array and query the array.
BOOL containsResponsibleUser = NO;
for (NSNumber *n in aGroup.responsibleUsers) {
if ([n isEqualTo:[NSNumber numberWithInteger: curUser.oID.integerValue]])
containsResponsibleUser = YES;
}
If you are indeed querying something like a group of users, I would recommend the first approach. If you are querying some kind of user, I would suggest a BOOL property responsible as the most efficient solution.

Sharepoint event handling.. which column changed?

I'm writing an event handler to handle the updating of a particular SPItem in a list. The event is asynchronous and I get the SPEvenItemProperties without a problem. What I would like to find out is which of the SPItems columns' actually fired the event. Anyone have any idea how?
Thanks in advance.
Your answer depends a bit on from where and how the SPListItem is retrieved. In a regular list, you do not have access to the previous values of the item. If you turn on versioning, you can get access to the previous versions, depending on permissions, of course.
For a document library you can use the SPItemEventProperties.BeforeProperties to get the previous metadata for a document.
For a document library you can try something like this:
foreach (DictionaryEntry key in properties.BeforeProperties)
{
string beforeKey = (string)key.Key;
string beforeValue = key.Value.ToString();
string afterValue = "";
if (properties.AfterProperties[beforeKey] != null)
{
afterValue = properties.AfterProperties[beforeKey].ToString();
if (afterValue != beforeValue)
{
// Changed...
}
}
}
.b
I think the best way to do this would be to look through the BeforeProperties and AfterProperties of the SPItemEventProperties and check which fields have different values.
These contain the values of all fields of the item before and after the event occurred.

Resources