本文介绍了如何强制UNIDIRECTIONAL多对多关系继续的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当一对多关系没有逆时,核心数据有问题。对相关属性所做的更改不会保留。这是我们许多人所面临的问题,因为它可以通过谷歌搜索找到。



这是问你是否有人找到了一个技巧/解决方法来实现持久性,


$ b b $ b
  • 即使文档中不建议单向关系,它们也不会被禁止。

  • 核心数据文档中概述了不需要反转的原因:当有大量项目链接到一个实体,每次添加项目时,反向关系正在加载大型NSSet。

  • 在员工/部门典型范例中,如果你有大量的员工能够属于几个部门,你需要从员工到部门的一对多的关系。您希望反转,因为每次员工链接到一个部门,一个(非常)大的NSSet必须加载,更新和保存。此外,如果部门实体从未被删除,则图形完整性易于维护。



    请不要回答这是核心数据的特征,而且反向关系是必须的。这不是这样说的,更像是一个bug而不是一个功能。发布错误报告无法解决当前部署系统的问题。



    编辑:Join实体解决方案
    此编辑是



    首先,为了回复你的第一个,我不想有一个多对多,但是一个真正的单向对多。您链接的同一页面的文字略低于您引用的文字:

    这就是说,如果没有解决方案强制核心数据生成并自动更新,您提出的添加连接实体的解决方案是一种方法。



    IMO,对于我的用例,连接实体甚至不需要与Department的关系。这个一对是没用的,并且可以由保存相关部门信息的连接实体的属性替换,例如它的objectID或其他索引属性。



    ie:

    DepartmentEmployee:

    属性:Dept_ix(整数)

    关系:employee(to-one,nullify)

    解决方案

    首先回覆您的意见:


    这正是department属性在连接关系中所做的。

    如果你看看生成的SQLite结构,您将看到Employee实体和Department实体之间的额外映射表,只保存他们的 int64 ids。



    现在,示例为:


    此示例请求类型为一对多的关系:

    员工 - >>部门(员工可能属于许多部门)

    相反的是:

    部门 - >雇员

    因为我们不能实现没有逆的多对多关系,所以我们必须实现关系的一方,只是为了确保我们遵守框架的实现。



    重新迭代:

    根据文档,我们知道没有多对多关系在没有定义逆关系的情况下将不会持续。

    ==>

    由于我们喜欢在没有逆的情况下建模关系,我们将它建模为耦合的一部分(将它建模为一个 - 许多会违反框架承诺的持久性)_
    想象它在一个文件夹中定义文件(文件可能不属于多个文件夹)或父子关系很有用。 >
    ==>

    我们必须将关系定义为:

    Department - > Employee(这不是很有意义,因为一个部门只能容纳一个员工不是真正的部门是不是)



    从另一个天使来看它(负面证据):

    假设我们想违背框架,定义一个没有逆的MANY-to-many关系。

    ==>

    这意味着我们只会实现它一个方向离开一个...多对一的关系或...多个关系对
    ==>

    这是同样的事情不是它(a - 多个关系,从entity1到entity2)

    ==>

    现在,如果我们有一对多的关系,我们选择不实现它的逆,我们可以选择实现多对多的部分? 我们无法,这将只显示一半的多对多关系
    ==>

    我们必须实施



    为了使一些更有意义,我会显示更合理的:

    部门 - >>员工
    所以我们对这个一对多关系的实现是:

    Department

    这将导致以下SQLite数据库结构:
    ¥b $ b ZDEPARTMENT:

    Z_PKholar
    Z_ENT

    Z_OPT

    ZNAME



    ZEMPLOYEE:

    Z_PK载
    Z_ENT

    Z_OPT

    ZDEPARTMENT(int)

    ZNAME
    <



    我们现在可以在Department上定义获取的属性,以获取所有员工属于它:

    employees 谓词:部门== $ FETCH_SOURCE



    您可以在部门的 prepareForDeletion 方法中执行此关系(未测试):

    (你将首先设置Department上的 userInfo 字典来保存强制类型)\\
    (我离开了Deny规则给读者: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];
    }

    }
    }];
    }
    }

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



    问候,

    There is a problem with core data when a to-many relationship has no inverse. Changes made to the related property do not persist. This is a problem many of us have faced, as it can be found by googling.

    This is to ask if some of you found a trick/workaround to achieve persistence, beside the obvious answer or adding an inverse relationship.

    Background:

    • Even if unidirectional relationship are discouraged in the documentation, they are not forbidden. The doc only insists on responsibility incurred when having no inverse.
    • The reason of not wanting an inverse is outlined in the core-data doc: when you have a large number of items linked to one entity the inverse relationship is loading a large NSSet each time an item is added. Consuming memory, possibly more than allowed for no reason.

    Example

    In employees/department typical paradigm, if you have a huge number of employees able to belong to several departments, you need a to-many relationship from employee to department. You do not want the inverse because each time an employee is linked to a department, a (very) large NSSet must be loaded, updated and saved. Moreover if the department entity is never deleted, graph integrity is easy to maintain.

    Please do not reply that this is a feature of core-data and that inverse relationship is mandatory. This is not stated as such and is more like a bug than a feature. Posting a bug report is not solving the point for current deployed systems.

    Edit: The Join entity solutionThis edit is to give more light and discussion to Dan Shelly's answer proposal below.

    First, to reply to your first, I'm not trying to have a many-to-many but a true unidirectional to-many. The very same page your linked has this text a bit below the one you quoted:

    That said your proposed solution of adding an join entity is a way to go if there is no solution to force core-data to generates and updates it automatically.

    IMO, and for my use case, the join entity does not even need to have the relationship to Department. This to-one is useless and may be replaced by a property of the join entity keeping related Department information, like its objectID or other indexed property to reach it.

    i.e:
    DepartmentEmployee:
    Properties: Dept_ix (integer)
    Relationships: employee (to-one,nullify)

    解决方案

    First a reply for your comment:

    This is exactly what the department property is doing in the joined relationship.
    If you would look at the generated SQLite structure, you will see and additional mapping table between the Employee entity and the Department entity, holding only their int64 ids.

    Now, the given example was:

    This example request a ONE-to-many relationship of the kind:
    Employee-->>Department (an Employee may belong to many departments)
    The inverse is:
    Department-->Employee
    Since we must not implement a many-to-many relationships without an inverse, we must implement the to-ONE side of the relationship, just to make sure we comply with the implementation of the framework.

    Re-iterating:
    By the documentation we know that no many-to-many relationship will NOT persist without an inverse relationship being defined.
    ==>
    Since we like to model the relationship without an inverse we will model it only as the to-ONE part of the coupling (modelling it as a to-many will violate the persistency promised by the framework)
    Think of it as useful for defining files in a folder (a file may not belong to more than one folder), or parent child relationship.
    ==>
    We must define the relationship as:
    Department-->Employee (Which does not make much sense since a department that can hold only one employee is not really a department is it)

    To look at it from another angel (negative proof):
    Suppose we would like to go against the framework and define a MANY-to-many relationship with no inverse.
    ==>
    That would mean that we will only implement it in one direction leaving a ... to-many relationship or ... MANY-to relationship
    ==>
    this is the same thing isn't it (a to-many relationship from and entity1 to entity2)
    ==>
    NOW, if we have a ONE-to-many relationship and we choose to not implement the inverse of it, we can choose to implement the to-many part? NO WE CANNOT, this will look as only half of a MANY-to-many relationship==>
    We MUST implement the ONE-to part of it.

    For making some more sense, I will show the more logical:
    Department-->>EmployeeSo our implementation for this ONE-to-many relationship would be:
    Department<--Employee

    This will result in the following SQLite DB structure:
    ZDEPARTMENT:
    Z_PK
    Z_ENT
    Z_OPT
    ZNAME

    ZEMPLOYEE:
    Z_PK
    Z_ENT
    Z_OPT
    ZDEPARTMENT (int)
    ZNAME

    We could now define a fetched property on Department to fetch all the employees belonging to it:
    employees predicate: department == $FETCH_SOURCE

    You can enforce this relationship in the prepareForDeletion method of Department (not tested):
    (You will first set the userInfo dictionary on Department to hold the type of enforcement)
    (I left the implementation of the 'Deny' rule to the reader :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"];
                    }
    
                }
            }];
        }
    }
    

    As I see it, this is all you can do with regard to inverse relationships.If you still believe you need a many-to-many relationship, please refer to my other answer.

    Regards,
    Dan.

    这篇关于如何强制UNIDIRECTIONAL多对多关系继续的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

    10-29 10:27