gpt4 book ai didi

ruby-on-rails - iOS 核心数据 : Approach for setting relationship for Rails polymorphic association

转载 作者:可可西里 更新时间:2023-11-01 05:58:58 26 4
gpt4 key购买 nike

我有一个 iOS 应用程序,它的核心数据模型模仿我的 Rails 后端数据模型。在我的 Rails 后端模型中,我对一些实体使用多态关联。我的 Rails 模型看起来像这样:

Airport < ActiveRecord::Base
has_many :reviews, :as => :reviewable

Restaurant < ActiveRecord::Base
has_many :reviews, :as => :reviewable

Review < ActiveRecord::Base
belongs_to :reviewable, :polymorphic => :true

在我的核心数据模型中,我有三个独立的实体,MyAirport、MyRestaurant 和 MyReview,它们具有如下所示的相关属性:

MyAirport
@property (nonatomic, retain) NSSet* reviews; //inverse is airport

MyRestaurant
@property (nonatomic, retain) NSSet* reviews; //inverse is restaurant

MyReview
@property (nonatomic, retain) NSNumber* reviewablId;
@property (nonatomic, retain) NSString* reviewableType;
@property (nonatomic, retain) MyAirport* airport; //inverse is reviews
@property (nonatomic, retain) MyRestaurant* restaurant; //inverse is reviews

我的问题与核心数据中的 MyReview 类有关。根据 reviewableId 和 reviewableType 中的值设置正确的核心数据关系(例如机场或餐厅)的最佳方法是什么?

我已经尝试了以下方法,但由于某种原因,所有方法似乎都有点不干净。一般来说,我需要确保在设置正确的关联之前我有两个可用的 reviewableId 和 reviewableType,这似乎是与感知清洁度相关的主要问题。从 JSON 混合这些模型对象时,我并没有真正控制 reviewableId 和 reviewableType 在新 MyReview 对象上的填充顺序。

1) reviewableId 和 reviewableType 中的一个或两者的自定义 setter - 我最终在每个 setter 方法中使用逻辑检查另一个属性的值,以确保在我可以在 MyReview 模型上设置机场或餐厅关系之前填充它目的。一般来说,这是可行的,但感觉不对,同时每个 setter 中都有一些难看的重复代码。

- (void)setReviewableId:(NSNumber*)reviewableId {
[self willChangeValueForKey:@"reviewableId"];
[self setPrimitiveReviewableId:reviewableId];
[self didChangeValueForKey:@"reviewableId"];

if (reviewableId && [reviewableId intValue] != 0 && self.reviewableType) {
if (self.airport == nil && [self.reviewableType isEqualToString:@"Airport"]) {

MyAirport myAirport = <... lookup MyAirport by airportId = reviewableId ...>
if (myAirport) {
self.airport = myAirport;
}

} else if (self.restaurant == nil && [self.reviewableType isEqualToString:@"Restaurant"]) {

MyRestaurant myRestaurant = <... lookup MyRestaurant by restaurantId = reviewableId ...>
if (myRestaurant) {
self.restaurant = myRestaurant;
}
}
}
}

- (void)setReviewableType:(NSString*)reviewableType {
[self willChangeValueForKey:@"reviewableType"];
[self setPrimitiveReviewableType:reviewableType];
[self didChangeValueForKey:@"reviewableType"];

if (self.reviewableId && [self.reviewableId intValue] != 0 && reviewableType) {
if (self.airport == nil && [reviewableType isEqualToString:@"Airport"]) {

MyAirport myAirport = <... lookup MyAirport by airportId = self.reviewableId ...>
if (myAirport) {
self.airport = myAirport;
}

} else if (self.restaurant == nil && [reviewableType isEqualToString:@"Restaurant"]) {

MyRestaurant myRestaurant = <... lookup MyRestaurant by restaurantId = self.reviewableId ...>
if (myRestaurant) {
self.restaurant = myRestaurant;
}
}
}
}

2) reviewableId 和 reviewableType 上的 KVO - 在 awakeFromInsert 和 awakeFromFetch 中,我通过 KVO 将模型对象注册到观察者自己的 reviewableId 和 reviewableType 属性。让对象观察自己感觉真的很难看,但至少我有一个方法来处理关联的填充,这似乎比 #1 有所改进。请注意,我确实在 dealloc 方法中使用 removeObserver:forKeyPath: 导致了一些崩溃(例如,崩溃表明我已经删除了一个不存在的观察者??),所以这与经过验证的代码相去甚远。

- (void)awakeFromFetch {
[super awakeFromFetch];
[self addObserver:self forKeyPath:@"reviewableId" options:0 context:nil];
[self addObserver:self forKeyPath:@"reviewableType" options:0 context:nil];
}

- (void)awakeFromInsert {
[super awakeFromInsert];
[self addObserver:self forKeyPath:@"reviewableId" options:0 context:nil];
[self addObserver:self forKeyPath:@"reviewableType" options:0 context:nil];
}

- (void)dealloc {
[self removeObserver:self forKeyPath:@"reviewableId"];
[self removeObserver:self forKeyPath:@"reviewableType"];
[super dealloc];
}

- (void)updatePolymorphicAssociations {
if (self.reviewableId && [self.reviewableId intValue] != 0 && self.reviewableType) {
if (self.airport == nil && [self.reviewableType isEqualToString:@"Airport"]) {

MyAirport myAirport = <... lookup MyAirport by airportId = self.reviewableId ...>
if (myAirport) {
self.airport = myAirport;
}

} else if (self.restaurant == nil && [self.reviewableType isEqualToString:@"Restaurant"]) {

MyRestaurant myRestaurant = <... lookup MyRestaurant by restaurantId = self.reviewableId ...>
if (myRestaurant) {
self.restaurant = myRestaurant;
}
}
}
}

- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context {
[self updatePolymorphicAssociations];
}

3) 使用上面的 updatePolymorphicAssociations 方法覆盖 willSave。这似乎可行,但它推迟了对关联的所有更改,直到我们去保存对象,这通常不是在我们对 reviewableId 和 reviewableType 进行初始更改时。这里似乎还有一些限制与通过后台线程插入一堆新的 MyReview 对象有关,可能与 willSave 有关,实际上导致我们刚刚保存的对象发生更改,从而再次触发 willSave。即使在 updatePolymorphicAssociations 中检查为零,我似乎仍然能够使用这种方法使应用程序崩溃。

- (void)updatePolymorphicAssociations {
if (self.reviewableId && [self.reviewableId intValue] != 0 && self.reviewableType) {
if (self.airport == nil && [self.reviewableType isEqualToString:@"Airport"]) {

MyAirport myAirport = <... lookup MyAirport by airportId = self.reviewableId ...>
if (myAirport) {
self.airport = myAirport;
}

} else if (self.restaurant == nil && [self.reviewableType isEqualToString:@"Restaurant"]) {

MyRestaurant myRestaurant = <... lookup MyRestaurant by restaurantId = self.reviewableId ...>
if (myRestaurant) {
self.restaurant = myRestaurant;
}
}
}
}

- (void)willSave {
[self updatePolymorphicAssociations];
}

4) 覆盖 didSave,而不是 willSave。这解决了我们在 #3 中遇到的后台大量导入的保存问题,但我们最终得到的是未保存的更改,这很丑陋。

因此,我在这里似乎有很多选择,但没有一个适合使用由 Rails 云数据库支持的 Core Data 解决 iOS 应用程序中似乎常见的问题。我是不是分析过度了?或者有更好的方法吗?

更新:请注意,目标是根据 reviewableType 是“Airport”还是“Restaurant”,仅设置 MyReview 上的一种关系。这种关系设置本身非常丑陋,但这就是我问这个问题的原因。 :)

最佳答案

您似乎犯了一个重大错误,即认为 Core Data 是关系数据库的对象包装器。它不是。 ActiveRecord 是关系数据库的对象包装器,这就是它必须使用多态关联等技术的原因。您不能将 Core Data 塞进关系包装器范例并期望获得优雅的设计。

根据我对您的数据模型的疑惑,您实际上并不需要 reviewablIdreviewableType 属性来实际创建图形本身。相反,您可以将它们替换为实体继承和关系。从看起来像这样的数据模型开始。

Review{
//... some review attributes
place<<-(required)->ReviewablePlace.reviews //... logically a review must always have a place that is reviewed
}

ReviewablePlace(abstract){
reviewableID:Number //... in case you have to fetch on this ID number later
reviews<-->>Review.place
}

Airport:Reviewable{
//... some airport specific attributes
}

Restaurant:Reviewable{
//... some restaurant specific attributes
}

这用对象关系替换了多态关联,并通过创建两个单独的子实体来区分两种类型的可审阅地点。由于 Review 实体与抽象 Reviewable 实体定义了关系,因此它也可以与任何 Reviewable 子实体建立关系。您可以通过 Reviewable 实体上的 reviewableID 获取,它将返回具有该 ID 的 AirportRestaurant 对象,您可以将其中一个弹出到 place 新的 Review 对象的关系。

要处理你的 JSON 对象,你会(在伪代码中):

if Airport
fetch on reviewableID
if fetch returns existing Airport managed object
break //don't want a duplicate so don't create an object
else
create new Airport managed object with reviewableID
break
if Restaurant
fetch on reviewableID
if fetch returns existing Restaurant managed object
break //don't want a duplicate so don't create an object
else
create new Restaurant managed object with reviewableID
break
if Review
fetch on reviewableID
if fetch returns Reviewable object of either subclass
create new Review object and assign fetched Reviewable object to the Review.place relationship
break
else
create new Airport or Resturant object using the JSON provided reviewableID and reviewableType info
create new Review object and assign the newly created Reviewable subclass object to the Review.place relationship
break

我认为这将为您提供一个完整的对象图,而无需跳过箍。在任何情况下,您在父帖子中考虑的大部分检查都可以用子实体和适当的关系代替。

关于ruby-on-rails - iOS 核心数据 : Approach for setting relationship for Rails polymorphic association,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5718821/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com