Non-optional to-many relationship allows nil or empty set - core-data

I have a sample data structure:
Table "Groups" and table "Items". Groups can contains zero or more items and item must be linked to minimum one or more groups:
Groups |--------- to-many, optional ---------->>|Items
---------|<<------- to-many, non-optional! -------|--------
groupName| |itemName
items | |groups
I create NSManagedObject subclasses. Both are trivial but here is Items:
class Items:NSManagedObject {
#NSManaged var itemName:String
#NSManaged var groups:Set<Groups> //attention: there is no ! or ?
}
In code below I expecting to catch error:
var item = Items()
item.itemName = "AAAA"
do {
try Items.moc.save() //moc - static field in Items "linked" to ManagedObjectContext
}
catch {
print(error)
}
But there is no errors! item saves to CoreData with empty groups. I can't figure out why? But if I make Items to Groups relation non-optional to-one (in class Items groups field became #NSManaged var group:Groups) exception throws as I expected.
I know, that I can implement in Items class function validateGroups, where I can check if groups nil or empty, but I want to know: is there my mistake that I cant find or it is Core Data bug (or feature)? More, I like to implement storage logic into database (in sql I very like triggers, I can't live without foreign keys, constraints etc).
So, please, help me to understand this. Thanks!

Problem solved, thanks to Willeke!
When I set minimum count in Item's entity relation properties problem disappeared.

Related

CoreData predicate - keypath not found

I have a Core Data object called User and another one called Conversation. I added a relationship between the two. The relationship is called lastConversation.
This is how it looks like:
I also added it to the User.swift class as so:
#NSManaged public var lastConversation: Conversation?
Now i'm trying to use this property in order to predicate out from CoreData. Here is a sample of a predicate that doesn't work for me:
NSPredicate(format: "lastConversation.uid == 123")
But when I run it, it crashes and says:
SQLCore dispatchRequest: exception handling request: <NSSQLFetchRequestContext: 0x600000a5d5e0> , keypath lastConversation.uid not found in entity LPUserEntity with userInfo of (null)
Can anyone help me?

Core Data delete object on reassignment

In Core Data, is it possible for have objects automatically deleted on reassignment?
For example if I have
class Person: NSManagedObject {
#NSManaged public var name: String?
#NSManaged public var group: Group?
}
class Group: NSManagedObject {
#NSManaged public var people: Set<Person>?
}
and assign a new set to a group's people property:
group.people = [some new set of <Person>]`
and then save the current context. I would like all the previous Person objects in the previous set to be deleted.
Do I have to to call delete on them manually before the new assignment or is there another way to do this?
As explained in the comments, it turns out that the Cascade Delete Rule does not delete a Group's Persons unless you delete the Group. So I've gutted my answer and replaced with this.
If you don't want to delete the Group, you must delete each Person and remove it from the relationship. It is not that bad, though…
if let people = group.people {
for person in people {
if let person = person as? NSManagedObject {
managedObjectContext.delete(person)
}
}
}
group.mutableSetValue(forKey: "people").removeAllObjects()
NSBatchDeleteRequest might also work if you configured it with a predicate to filter only Persons in the relevant group, but unless you have thousands of Persons to delete I would not bother with it.

how can i fill controller with data - SQL Function in Entity Framework?

i have create an sql function in my database that take to Date params and get data from 5 tables.
after that add it to project as entity framework from database and the code generated is:
[DbFunction("Dr_EmploEntities", "SelectEmployee")]
public virtual IQueryable SelectEmployee(Nullable frm_date, Nullable to_date)
{
var frm_dateParameter = frm_date.HasValue ?
new ObjectParameter("frm_date", frm_date) :
new ObjectParameter("frm_date", typeof(DateTime));
var to_dateParameter = to_date.HasValue ?
new ObjectParameter("to_date", to_date) :
new ObjectParameter("to_date", typeof(DateTime));
return ((IObjectContextAdapter)this).ObjectContext.CreateQuery("[Dr_EmploEntities].[SelectEmployee](#frm_date, #to_date)", frm_dateParameter, to_dateParameter);
}
public DbSet SelectEmployee_Result { get; set; }
as you see i have now "SelectEmployee_Result" that don't take any params, and "SelectEmployee" that take two date params.
after that i have create an controller for "SelectEmployee_Result" class.
after that i run my project Index View that working with "SelectEmployee_Result" class give me err:
"The type 'SelectEmployee_Result' is mapped as a complex type. The Set method, DbSet objects, and DbEntityEntry objects can only be used with entity types, not complex types."
and i make breakpoint and see that "SelectEmployee_Result" has no data so i change the Index Code in controller and fill "SelectEmployee" with two date params
and when run got same err msg too.
so how can i fill "SelectEmployee_Result" from the beginning with data between two dates to let me use it in all views ?
all what i need here is view data i got i edit before saving it in database Like using DataTable but i need to do that from Entity with sql function
and what is difference between "SelectEmployee" that is my function name and that is need two params and "SelectEmployee_Result"?

Relation between Retieve AND Update in a Dynamic CRM PLUGIN

Is there a relation between Retrieve and Update in a Dynamic CRM Plugin?
For example if I am retrieving only one field:
Entity e = (Entity)service.Retrieve("EntityLogicalName", EntityGuid,
new ColumnSet(new string[] {"entityid"}));
Can I update another field in the Entity e that has NOT been retrieved?
For example:
e.Attributes["AnotherEntityField1] = "test1";
e.Attributes["AnotherEntityField2] = "test2";
service.update(e);
By NOT including all fields that to be updated in the Retrieve, may this cause some hidden issues?
Assuming, as it appears, that you are just retrieving the entity's primary key, entityid, you won't need to do the retrieve.
Entity e = new Entity("EntityLogicalName") { Id = EntityGuid };
e.Attributes.Add("AnotherEntityField1", "test1");
e.Attributes.Add("AnotherEntityField2", "test2");
service.Update(e);
If you are doing a retrieve to confirm the record exists you need to try/catch or use a retrieve multiple since a Retrieve will throw an exception if the record does not exist.
What you are trying to do is perfectly acceptable and won't cause any problems. Since you obtained the Entity instance via a Retrieve operation the required LogicalName and Id will be set correctly for an update.
Your code would need to read as below for adding new attributes not retrieved initially otherwise you'll get a KeyNotFoundException as the Entity type is just a wrapper over Dictionary<string,string>.
e.Attributes.Add("AnotherEntityField2","test2");
When you're trying to update an entity you don't need that an field exists in the attributes colletion, but to avoid the exception "The given key is not presented in the dictionary" is a good practise to check first if the Attributes Colletion contains the field you want to updated. If yes just update it otherwise you have to add it to the Attributes Colletion of the entity.
if(e.Attributes.Contains("AnotherEntityField1"))
{
e.Attributes["AnotherEntityField1"] = "test1";
}
else
{
e.Attributes.Add("AnotherEntityField1", "test1");
}
// now update operation

Fill CoreData ManagedObject property based on another object property

I have app that stores tree structure in CoreData.
There is an ManagedObject, "Item", and it has attributes:
itemId (string)
List item
title (string)
parentId (string)
parent (relationship to Item)
parentTitle (string)
parentId points to another Item object.
How do I make property parentTitle to be filled automatically with title of parent Item ?
While Martin's suggestion is a good solution for derived values, my question on yours is, why would you want this? You are not manipulating the value from the parent at all, ever. Since you are just accessing it, access the parent directly via KVC such as:
Item *item = ...;
NSString *title = [item valueForKeyPath:#"parent.title"];
//Do something with title
The only time you would want to use the keyPathsForValues... functionality is if you are changing something based on that value. If you are just accessing it, use KVC directly.
This is a possibility to achieve the desired functionality:
// implement in Item.m
// manages KVO notifications
+ (NSSet *)keyPathsForValuesAffectingParentTitle
{
return [NSSet setWithObjects:#"parent.title", nil];
}
// getter for parentTitle
- (NSString*) parentTitle
{
return [self valueForKeyPath:#"parent.title"];
}
additionally declare the property for parentTitle as readonly in Item.h
There is no need to declare a Core Data attribute "parentTitle".
The only problem I see with this solution is the following:
Item A is parent of item B
A gets turned into fault
B is still active and some View is bound to B.parentTitle
The view gets a notification because of the dependency declared with keyPathsForValuesAffecting, still object A is already faulted (and on shutdown unable to be unfaulted again) does Core Data manage such faulting&observation problems automatically?

Resources