开发者

Core Data - Following Keypaths

开发者 https://www.devze.com 2023-01-06 03:10 出处:网络
I am new to Core Data and am stumbling on the right way to set up a query. My managed object model includes the classes Apartment, Lease, and what I 开发者_JAVA技巧would otherwise call a join table c

I am new to Core Data and am stumbling on the right way to set up a query.

My managed object model includes the classes Apartment, Lease, and what I 开发者_JAVA技巧would otherwise call a join table called ApartmentLease. This looks like:

/-----------------\      /-----------------\      /-----------------\
| Apartment       |      | ApartmentLease  |      | Lease           |
|-----------------|      |-----------------|      |-----------------|
| number          |      | startOn         |      | occupantName    |
|-----------------|      | endOn           |      | monthlyRate     |
| apartmentLeases |-\    |-----------------|      | occupantPhone   |
\-----------------/  \->>| apartment       |      |-----------------|
                         | lease           |<<----|apartmentLeases  |
                         \-----------------/      \-----------------/

So what I have tried to model is that a Lease can have many Apartments and each Apartment in the lease has its own start and ending dates.

So my question is: Given a range of dates, how can I query the Apartment object and get back an array of all the Leases that occupied the Apartment during that date range?

Thanks and sorry for my horrible ASCII art!

Bert


Instead of querying the Apartment entity, query your ApartmentLease entity.

[NSPredicate predicateWithFormat:@"startOn <= %@ && endOn >= %@", referenceDate, referenceDate];

Then once you have the array of ApartmentLease entities, you can retrieve the apartment entities via:

NSArray *apartments = [apartmentLeaseArray valueForKeyPath:@"@distinctUnionOfObjects.apartment"];

Now you have an array of Apartment entities that match your search criteria.

update

If you already have a reference to the apartment then just get the set of apartment leases and filter against that set for a lease that includes the date in question. There is no reason to go through a NSFetchRequest if you already have the apartment. Think of Core Data as an object graph, not a database. All of the relationships are already pre-populated, you don't need to fetch them, just walk the object graph.


Marcus S. Zarra answer is the correct one for you actual question but you might want to reconsider your data model. You definitely don't want to try to think of Core Data in terms of relational databases.

In a good data model, each entity should model a real world object, event or condition. In this case, your ApartmentLease entity doesn't actually represent anything real, its just there to make the code work. That's a red flag.

You really only need Apartment and Lease entities. The Lease entity should accurately model the a real lease agreement. Since a real lease has its own start and end dates, that data should be stored in the attributes of the lease entity and not another entity.

You really only need:

Apartment {
    number:int;
    leases<--(optional,cascade)-->>lease.apartment
} 

Lease{
    startOn:date;
    endOn:date;
    occupantName:string;
    monthlyRate:float;
    occupantPhone:string
    apartment<<--(required,nullify)->Apartment.leases
}

Then you just take Marcus's predicate and apply it to the Apartment.leases to find the leases in the date range.

NSManageObject *anApartment= // which every apartment whose leases you want to examine
NSPredicate *rangePred=[NSPredicate predicateWithFormat:@"startOn <= %@ && endOn >= %@", startReferenceDate, endReferenceDate];
NSSet *leases=[anAparment valueForkey:@"leases"];
NSSet *leasesInDateRange=[leases filteredSetUsingPredicate:rangePred];

Remember that these entities are actually objects at runtime so if you create customer NSManagedObject subclasses, you can embed logic in them. For example, you could create transient bool attributes for the lease entity of: inForce, expired. Then have custom getters like so:

-(BOOL) inForce{
    BOOL isInForce;
    NSDate *today=[NSDate now];
    if (self.starOn<today<self.endOn){
        isInForce=YES;
    }else{
        isInForce=NO;
    }
    return isInForce;
}

Then you can fetch with predicates that look for all leases that are inForce, expired or pending or you can fetch all apartments whose leases are in one of those states.

0

精彩评论

暂无评论...
验证码 换一张
取 消