iPhone Development - Query related records using CoreData - iphone

I have a case where i have three entities with one-to-many and one-to-many relationships:
Entity A (Entity B relationhip),
Entity B (Entity A relationship, Entity C relationship),
Entity C (Entity B relationhip)
I have the reference of Entity A, and now i want to fetch all the related Entity C records. How can i do that? (with least amount of code)
Edit: Here's another way to put it.
Can we perform joins with CoreData. For example, (and this is a very crude example), We have a following entity-relationship:
Grand Parent (1)---(m) Parent
Parent (1)---(m) Child
So, now if i have "Albert" the Grand Parent, and i want to get all his grand children, how can i do that?

In case someone else stumble across a similar situation, here's what worked for me:
NSArray *allFieldValues = [myEntityA valueForKeyPath:#"Entity B relationship.Entity C relationship.requiredFieldInEntityC"];
I was mainly interesting in reading the data of a single field in Entity C (that's linked to myEntityA object). The key concept here is that "don't think of CoreData as a 'database'".

Related

Core Data delete only the relationship link between Many-to-Many - not any objects

This is driving me nuts and I can't find anything where someone else has asked the same question. It can't be an unusual situation.
I have a Student entity and a Classes entity and both are bi-directional
Student<<-->>Classes
A Student can be assigned to many Classes and Classes can have many students
When a Student drops out of a given class, I want to remove the link between the particular student and the class - but without deleting either the student or the class objects.
All my attempts have deleted the student or the class object.
How do I remove the relationship without removing the objects ?
Thank You to Joakim Danielson ! The answer was there... I just wasn't aware... Core Data creates a func for the entity relationship.
As an example
entity Students has a relationship named Classes (destination = Classes entity)
entity Classes has a relationship named Students (destination = Students entity)
Core Data creates a func for each of the entity relationships:
.removeFromClasses()
.removeFromStudents()
these remove the relationship link from each of the respective relationships.
In order to remove the relationship completely, I execute both func - the entity objects both remain but are no longer linked !

Coredata relationship entity creation

I have a question about the coredata relationship.
Essentially, if I have 1 entity called i.e parent and the other entity which it has a relationship with is children and it is inverse.
If I create the parent entity, will it create the children entity as well? I 've set the "parentchildrenrelationship" to optional but it looks like every time I create the parent entity, it creates the children entity.
Is that something normal ? Thanks
It is not normal. Are you sure you're not creating the children entity otherwise? Just because you create one entity does not mean it creates the entities that it is referencing.
Core Data should not automatically create entities to fulfill relationships, especially if the relationship is optional. The value of children should either be nil (for a one-to-one relationship) or an empty NSSet or NSArray (for a one-to-many relationship, depending on ordering) for a newly created parent entity.

EF 4.1 loading filtered child collections not working for many-to-many

I've been looking at Applying filters when explicitly loading related entities and could not get it to work for a many-to-many relationship.
I created a simple model:
Brief description:
A Student can take many Courses and a Course can have many Students.
A Student can make many Presentation, but a Presentation can be made by only one Student.
So what we have is a many-to-many relationship between Students and Courses, as well as a one-to-many relationship between Student and Presentations.
I've also added one Student, one Course and one Presentation related to each other.
Here is the code I am running:
class Program
{
static void Main()
{
using (var context = new SportsModelContainer())
{
context.Configuration.LazyLoadingEnabled = false;
context.Configuration.ProxyCreationEnabled = false;
Student student = context.Students.Find(1);
context.
Entry(student).
Collection(s => s.Presentations).
Query().
Where(p => p.Id == 1).
Load();
context.
Entry(student).
Collection(s => s.Courses).
Query().
Where(c => c.Id == 1).
Load();
// Trying to run Load without calling Query() first
context.Entry(student).Collection(s => s.Courses).Load();
}
}
}
After loading the presentations I see that the count for Presentations changed from 0 to 1: . However, after doing the same with Courses nothing changes:
So I try to load the courses without calling Query and it works as expected:
(I removed the Where clause to further highlight the point - the last two loading attempts only differ by the "Query()" call)
Now, the only difference I see is that one relationship is one-to-many while the other one is many-to-many. Is this an EF bug, or am I missing something?
And btw, I checked the SQL calls for the last two Course-loading attempts, and they are 100% identical, so it seems that it's EF that fails to populate the collection.
I could reproduce exactly the behaviour you describe. What I got working is this:
context.Entry(student)
.Collection(s => s.Courses)
.Query()
.Include(c => c.Students)
.Where(c => c.Id == 1)
.Load();
I don't know why we should be forced also to load the other side of the many-to-many relationship (Include(...)) when we only want to load one collection. For me it feels indeed like a bug unless I missed some hidden reason for this requirement which is documented somewhere or not.
Edit
Another result: Your original query (without Include) ...
context.Entry(student)
.Collection(s => s.Courses)
.Query()
.Where(c => c.Id == 1)
.Load();
... actually loads the courses into the DbContext as ...
var localCollection = context.Courses.Local;
... shows. The course with Id 1 is indeed in this collection which means: loaded into the context. But it's not in the child collection of the student object.
Edit 2
Perhaps it is not a bug.
First of all: We are using here two different versions of Load:
DbCollectionEntry<TEntity, TElement>.Load()
Intellisense says:
Loads the collection of entities from
the database. Note that entities that
already exist in the context are not
overwritten with values from the
database.
For the other version (extension method of IQueryable) ...
DbExtensions.Load(this IQueryable source);
... Intellisense says:
Enumerates the query such that for
server queries such as those of
System.Data.Entity.DbSet,
System.Data.Objects.ObjectSet,
System.Data.Objects.ObjectQuery,
and others the results of the query
will be loaded into the associated
System.Data.Entity.DbContext,
System.Data.Objects.ObjectContext or
other cache on the client. This is
equivalent to calling ToList and then
throwing away the list without the
overhead of actually creating the
list.
So, in this version it is not guaranteed that the child collection is populated, only that the objects are loaded into the context.
The question remains: Why gets the Presentations collection populated but not the Courses collection. And I think the answer is: Because of Relationship Span.
Relationship Span is a feature in EF which fixes automatically relationships between objects which are in the context or which are just loaded into the context. But this doesn't happen for all types of relationships. It happens only if the multiplicity is 0 or 1 on one end.
In our example it means: When we load the Presentations into the context (by our filtered explicit query), EF also loads the foreign key of the Presentation entites to the Student entity - "transparently", which means, no matter if the FK is exposed as property in the model of not. This loaded FK allows EF to recognize that the loaded Presentations belong to the Student entity which is already in the context.
But this is not the case for the Courses collection. A course does not have a foreign key to the Student entity. There is the many-to-many join-table in between. So, when we load the Courses EF does not recognize that those courses belong to the Student which is in the context, and therefore doesn't fix the navigation collection in the Student entity.
EF does this automatic fixup only for references (not collections) for performance reasons:
To fix relationship, EF transparently
rewrites the query to bring
relationship info for all relations
which has multiplicity of 0..1 or1 on
the other end; in other words
navigation properties that are entity
reference. If an entity has
relationship with multiplicity of
greater then 1, EF will not bring back
the relationship info because it could
be performance hit and as compared to
bringing a single foreign along with
rest of the record. Bringing
relationship info means retrieving all
the foreign keys the records has.
Quote from page 128 of Zeeshan Hirani's in depth guide to EF.
It is based on EF 4 and ObjectContext but I think this is still valid in EF 4.1 as DbContext is mainly a wrapper around ObjectContext.
Unfortunately rather complex stuff to keep in mind when using Load.
And another Edit
So, what can we do when we want to explicitely load one filtered side of a many-to-many relationship? Perhaps only this:
student.Courses = context.Entry(student)
.Collection(s => s.Courses)
.Query()
.Where(c => c.Id == 1)
.ToList();

How Do I Create And Update A Many To Many Relationship With EF

I am using the Entity Framework with SQL Server. I have a many to many relationship between 2 tables. I have created a join table with just the primary key fields of the 2 tables. In the designer, the 2 tables now have a navigation property to the other with return types of Collection of X where X is the other entity. So far, everything just as it should be. The setup looks correct.
Task TaskProducts Product
========== ============ =======
TaskID TaskID ProductID
Description ProductID Name
Not every task will have a product or products associated with it. What do I assign to the Products navigation property of the Task table when there is no associated Product for that Task?
Do I build up a EntityCollection collection with the Product entities and assign that to the Products navigation property on the Task entity when I do have Product entities?
When doing updates(adding, removing and changing) to the Products navigation property on the Task entity, do I work with it like any other collection? Are there any special things to look out for?
I would be interested in any help working with many to many relationships in the Entity Framework.
Edit(11/17/2009)
One thing I learned is that to a many to many relationship work with a join table, BOTH fields in the join table need to be marked as primary keys;
MSDN has good documentation on managing many-to-many relationships in the Entity Framework:
http://msdn.microsoft.com/en-us/library/bb738695.aspx
The prescriptive guidance for inserts is to call the "Add" method on the entity collection and specify the related object (versus setting the Value property on the entity reference for a one-to-many relationship.)
Updates are handled just like any other EF update... load the desired object, set the changed properties and call SaveChanges on the context.
Deletes are handled the same as well, call DeleteObject on the context and then SaveChanges.

Map classes to database with ado.net

I want to know if there is way to create a database out of existing classes with the ado.net entity framework or to map existing classes to a database.
I looked for tutorials and only found ways to create the classes with the entity model designer.
As an example I have the class Bird with Properties Length and Age
On the database I have a table named Bird with columns Length and Age
Now I don't want the designer to create new classes out of the database. Instead I want to map the Class Bird directly to the table Bird. With Linq2Sql this was possible by creating the mapping manually. Is there a possibility in the ado.net entity framework?
With kind regards
Sebastian
What's the difference between mapping a class C onto a table T or mapping T onto a class C ?
O/R mapping isn't about mapping classes to tables, it's about defining an entity model and projecting it to tables AND classes simultaneously. After all, your classes and tables don't fall out of the sky: they're based on definitions you have, e.g. there has to be an entity customer, with fields A, B and C, and THEN you're defining the entity Customer with fields A, B and C which leads to a table Customer with fields A, B and C and a class Customer with fields / properties A, B and C and the mapping between them, because they represent the same entity