如何强制UNIDIRECTIONAL与

核心数据存在问题,当多对一关系没有反转时。 对相关属性所做的更改不会持续。 这是我们很多人面临的问题,因为它可以通过Google搜索找到。

这是为了询问你们中的一些人是否找到了一种诀窍/解决方法来实现持久性,除了明显的答案或添加了反向关系之外。

背景

  • 即使文件中不鼓励单向关系,也不禁止它们。 该文件只坚持在没有反作用时发生的责任。
  • 核心数据文档中概述了不想反过来的原因:当有大量项目链接到一个实体时,反向关系会在每次添加项目时加载大的NSSet。 消费记忆,可能超过无故原因。
  • 在员工/部门典型范例中,如果拥有数量庞大的员工能够属于多个部门,则需要从员工到部门的多对多关系。 你不想逆,因为每个雇员被链接到一个部门的时候,一个(非常)大的NSSet必须加载,更新和保存。 此外,如果部门实体从未被删除,图表完整性很容易维护。

    请不要回复这是核心数据的一项功能,而且这种反向关系是强制性的。 这并非如此,更像是一个bug而不是一个功能。 发布错误报告并不能解决当前部署系统的问题。

    编辑:加入实体解决方案此编辑旨在让丹·谢利的答案建议更多的提示和讨论。

    首先,为了回复你的第一个问题,我并不是想要多对多,而是一个真正的单向多对多。 您链接的页面与您引用的页面相比稍低一点:

    单向关系

    在两个方向上建立关系并非严格必要。 在某些情况下,它可能不是有用的,例如,当一对多关系可能有大量的目标对象时,并且很少可能会遍历关系(您可能希望确保您不会不必要地在关系目的地处的大量对象)。 但是,如果不在两个方向上建立关系模型,都会对您承担很多责任,以确保对象图的一致性,进行更改跟踪以及撤消管理。

    这表示,如果没有解决方案强制核心数据自动生成和更新,那么您提出的添加联合实体的解决方案是一种方法。

    国际海事组织,并为我的使用情况下,联合实体甚至不需要与部门的关系。 这一对一是无用的,并且可以由保持相关部门信息的连接实体的属性取代,例如其对象ID或其他索引属性以达到它。

    即:
    DepartmentEmployee:
    属性:Dept_ix(整数)
    关系:员工(一对一,无效)



    这是一个很好的问题。

    但首先是:
    它在文档中明确指出:

    “重要的是:你必须在两个方向上定义多对多的关系 - 也就是说,你必须指定两个关系,每个关系都是另一个关系的反向关系。你不能只在一个方向上定义一个多对多的关系,并尝试把它当作多对多的使用,如果你这样做,你最终会遇到参照完整性问题。“

    从来没有,让我们描述这个问题(产生的数据库)
    定义多对多关系时,生成的数据库不会添加额外的表来映射关系。
    它只在对多关系一端的实体上设置一个属性,等于引用它的最后一个项目。

    例:

    模型:
    实体:部门
    关系:无
    属性:name(字符串)

    实体:员工
    关系:部门(多对多,无行动)
    属性:名称

    结果数据库:
    ZDEPARTMENT:
    Z_PK
    Z_ENT
    Z_OPT
    Z2DEPARTMENTS(int)
    ZNAME

    ZEMPLOYEE:
    Z_PK
    Z_ENT
    Z_OPT
    ZNAME

    这种结构显然会导致数据不一致。

    解决方案将包含一个实体: DepartmentEmployee在两个方向上建模多对多关系,但其中一个将是单向的(Department - > DepartmentEmployee):

    DepartmentEmployee:
    关系:部门(一对一,不采取行动),员工(一对一,无效)

    并且在删除部门对象时必须维护表格。

    希望这有些道理:)


    首先回复你的评论:

    国际海事组织,并为我的使用情况下,联合实体甚至不需要与部门的关系。 这一对一是无用的,并且可以由保持相关部门信息的连接实体的属性取代,例如其对象ID或其他索引属性以达到它。

    这正是部门财产在联合关系中所做的。
    如果您要查看生成的SQLite结构,您将看到Employee实体和Department实体之间的附加映射表,仅保存它们的int64 ID。

    现在,给出的例子是:

    在员工/部门典型范例中,如果拥有数量庞大的员工能够属于多个部门,则需要从员工到部门的多对多关系。 您不需要反过来,因为每次员工链接到部门时,必须加载,更新和保存(非常)大的NSSet。 此外,如果部门实体从未被删除,图表完整性很容易维护。 一个简单的一对多的关系,没有反转,可以很容易地实现。
    您可以将它视为关系“多边”一侧的对象上的另一个属性。

    这个例子请求了一种一对多的关系:
    员工 - >>部门(员工可能属于多个部门)
    反过来是:
    部门 - >员工
    由于我们不能实现多对多的关系而没有相反的关系,所以我们必须实现关系的一方,以确保我们遵守框架的实施。

    重新迭代:
    通过文档我们知道,如果没有定义反向关系,不会存在多对多关系。
    ==>
    由于我们喜欢在没有反转的情况下对关系进行建模,因此我们只会将它建模为耦合的to-one部分(将它建模为to-many会违反框架所承诺的持久性)
    把它看作在文件夹中定义文件(一个文件可能不属于多个文件夹)或父子关系是有用的。
    ==>
    我们必须将关系定义为:
    部门 - >员工(这是没有什么道理的,因为只有一个员工的部门实际上不是一个部门)

    从另一个天使来看它(负面证据):
    假设我们想要违背框架并且定义一个多对多的关系而不是相反的。
    ==>
    这意味着我们只会在一个方向上实施,留下......多对多的关系或......多对多的关系
    ==>
    这同样是不同的(从entity1到entity2的多对多关系)
    ==>
    现在,如果我们有一对多的关系,而且我们选择不实现它的逆,我们可以选择实现多对多的部分? 我们不能 ,这只会成为多对多关系的一半==>
    我们必须实施它的一部分。

    为了更有意义,我将展示更合乎逻辑的:
    部门 - >>员工因此,我们对此一对多关系的实施将是:
    系< - 员工

    这将导致以下SQLite数据库结构:
    ZDEPARTMENT:
    Z_PK
    Z_ENT
    Z_OPT
    ZNAME

    ZEMPLOYEE:
    Z_PK
    Z_ENT
    Z_OPT
    ZDEPARTMENT(int)
    ZNAME

    我们现在可以在Department上定义一个抓取的属性来获取属于它的所有员工:
    employees谓词: department == $FETCH_SOURCE

    您可以在Department的prepareForDeletion方法中强制执行此关系(未测试):
    (您将首先在Department上设置userInfo字典以保存强制类型)
    (我给读者留下了“拒绝”规则的实施:D)

    - (void) prepareForDeletion
    {
        [super prepareForDeletion];
        NSEntityDescription* entity = [self entity];
        NSDictionary* dict = [entity userInfo] ;
        if ([dict count]) {
            [dict enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSString* value, BOOL *stop) {
                NSArray* arr = [self valueForKey:key];
                if( [value isEqualToString:@"cascade"]) {
                    for (NSManagedObject* obj in arr) {
                        [[self managedObjectContext] deleteObject:obj];
                    }
                } else if ( [value isEqualToString:@"nullify"] ) {
                    NSArray* arr = [self valueForKey:key];
                    for (NSManagedObject* obj in arr) {
                        [obj setValue:nil forKey:@"department"];
                    }
    
                }
            }];
        }
    }
    

    正如我所看到的,这是关于反向关系所能做的。 如果你仍然相信你需要多对多的关系,请参考我的其他答案。

    问候,
    担。


    您是否考虑彻底废除关系并以编程方式管理员工的外键?

    如果您有一个用户界面来设置现有部门列表中的属性(选择列表等),您可以简单地从该列表中获取主键,并将其指定为员工的departmentID属性。

    然后,您应该能够在Employee对象上实现validateDepartmentID:error方法,该方法检查给定的departmentID是否有效(即位于部门的提取列表中)和/或不为null,以便保持Employee和部。

    在提取部门中的员工列表时,您可以使用提取的属性,也可以将实例方法添加到部门,该部门返回包含部门员工列表的NSFetchedResultsController实例。

    您唯一需要做的其他事情是在您的Department类中注入一些删除逻辑(可能在-prepareForDeletion )以更新任何受影响的子记录上的departmentID 。 这取决于你的业务逻辑。

    属性验证的Apple文档覆盖了-prepareForDeletion-validateValue:forKey:error如果您不熟悉它们。

    链接地址: http://www.djcxy.com/p/60637.html

    上一篇: How to force UNIDIRECTIONAL to

    下一篇: NSPredicate with SUBQUERY does not work