핵심 데이터 마이그레이션 : 한 엔티티에서 상위 엔티티로 관계를 변경 한 후 예외

로봇 스페이서

Car엔터티 를 포함하는 코어 데이터 모델이 있으며 엔터티를 예로 들어 보겠습니다 EngineData. 이것은 일대일 관계입니다.

내 앱의 새 버전에서 트럭을 추가하고 싶습니다. 그래서 저는 Core Data 모델의 새 버전을 만들었습니다. 이제 Vehicle의 상위 엔터티 인 엔터티가 Car있습니다. 부모 엔터티 Truck로도 있는 새 엔터티를 추가했습니다 Vehicle. 의 경우 EngineData역 관계는 ​​일반적으로 이름이 지정 object되었으므로 대상 엔터티는에서 Car변경 됩니다 Vehicle.

이것이 가벼운 마이그레이션으로 작동할지 완전히 확신하지 못했지만 몇 주 전에 처음 변경했으며 지금까지는 괜찮아 보였습니다. 속성 EngineData사용하여 기존 데이터를 가져오고 업데이트하는 코드가 있으며 거기에 문제가 없습니다. 그러나 내 앱에는 매번 충돌을 일으키는 단일 핵심 데이터 가져 오기가 있습니다. 충돌을 일으키기 위해해야 ​​할 일은 모든 객체를 간단히 가져 오는 것입니다 .CarengineDataEngineData

do {
    let request: NSFetchRequest<EngineData> = EngineData.fetchRequest()
    let objects = try context.fetch(request)
} catch {
    NSLog("Error fetching data: \(error)")
}

context.fetch라인, 나는 예외를 얻을 :

[error] error: Background Core Data task threw an exception.  Exception = *** -[__NSArrayM objectAtIndex:]: index 18446744073709551615 beyond bounds [0 .. 10] and userInfo = (null)
CoreData: error: Background Core Data task threw an exception.  Exception = *** -[__NSArrayM objectAtIndex:]: index 18446744073709551615 beyond bounds [0 .. 10] and userInfo = (null)

그리고 실제로 이러한 객체로 작업을 시도하면 앱이 충돌 할 때까지 몇 가지 예외가 발생합니다.

[General] An uncaught exception was raised
[General] *** -[__NSArrayM objectAtIndex:]: index 18446744073709551615 beyond bounds [0 .. 10]

0   CoreFoundation                      0x00007fff8861937b __exceptionPreprocess + 171
1   libobjc.A.dylib                     0x00007fff9d40d48d objc_exception_throw + 48
2   CoreFoundation                      0x00007fff88532b5c -[__NSArrayM objectAtIndex:] + 204
3   CoreData                            0x00007fff881978ed -[NSSQLRow newObjectIDForToOne:] + 253
4   CoreData                            0x00007fff8819770f -[NSSQLRow _validateToOnes] + 399
5   CoreData                            0x00007fff88197571 -[NSSQLRow knownKeyValuesPointer] + 33
6   CoreData                            0x00007fff88191868 _prepareResultsFromResultSet + 4312
7   CoreData                            0x00007fff8818e47b newFetchedRowsForFetchPlan_MT + 3387
8   CoreData                            0x00007fff8835f6d7 _executeFetchRequest + 55
9   CoreData                            0x00007fff8828bb35 -[NSSQLFetchRequestContext executeRequestUsingConnection:] + 53
10  CoreData                            0x00007fff8832c9c8 __52-[NSSQLDefaultConnectionManager handleStoreRequest:]_block_invoke + 216
11  libdispatch.dylib                   0x000000010105478c _dispatch_client_callout + 8
12  libdispatch.dylib                   0x00000001010555ad _dispatch_barrier_sync_f_invoke + 307
13  CoreData                            0x00007fff8832c89d -[NSSQLDefaultConnectionManager handleStoreRequest:] + 237
14  CoreData                            0x00007fff88286c86 -[NSSQLCoreDispatchManager routeStoreRequest:] + 310
15  CoreData                            0x00007fff88261189 -[NSSQLCore dispatchRequest:withRetries:] + 233
16  CoreData                            0x00007fff8825e21d -[NSSQLCore processFetchRequest:inContext:] + 93
17  CoreData                            0x00007fff8817d218 -[NSSQLCore executeRequest:withContext:error:] + 568
18  CoreData                            0x00007fff882436de __65-[NSPersistentStoreCoordinator executeRequest:withContext:error:]_block_invoke + 5486
19  CoreData                            0x00007fff8823a347 -[NSPersistentStoreCoordinator _routeHeavyweightBlock:] + 407
20  CoreData                            0x00007fff8817cd9e -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 654
21  CoreData                            0x00007fff8817af51 -[NSManagedObjectContext executeFetchRequest:error:] + 593
22  libswiftCoreData.dylib              0x0000000100c91648 _TFE8CoreDataCSo22NSManagedObjectContext5fetchuRxSo20NSFetchRequestResultrfzGCSo14NSFetchRequestx_GSax_ + 56

나는 깃발 -com.apple.CoreData.SQLDebug 1이 나에게 유용한 정보를 줄 것이라고 생각 했지만, 여기서는 그다지 도움이되는 것이 보이지 않는다.

CoreData: annotation: Connecting to sqlite database file at "/Users/name/Library/Group Containers/Folder/Database.sqlite"
CoreData: sql: pragma recursive_triggers=1
CoreData: sql: pragma journal_mode=wal
CoreData: sql: SELECT Z_VERSION, Z_UUID, Z_PLIST FROM Z_METADATA
CoreData: sql: SELECT TBL_NAME FROM SQLITE_MASTER WHERE TBL_NAME = 'Z_MODELCACHE'
CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZDATA, t0.ZOBJECT, t0.Z9_OBJECT FROM ZENGINEDATA t0 
2017-04-28 16:18:41.693548-0400 AppName[95979:11442888] [error] error: Background Core Data task threw an exception.  Exception = *** -[__NSArrayM objectAtIndex:]: index 18446744073709551615 beyond bounds [0 .. 10] and userInfo = (null)
CoreData: error: Background Core Data task threw an exception.  Exception = *** -[__NSArrayM objectAtIndex:]: index 18446744073709551615 beyond bounds [0 .. 10] and userInfo = (null)
CoreData: annotation: sql connection fetch time: 0.0065s
CoreData: annotation: fetch using NSSQLiteStatement <0x6080004805a0> on entity 'ENGINEDATA' with sql text 'SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZDATA, t0.ZOBJECT, t0.Z9_OBJECT FROM ZENGINEDATA t0 ' returned 1185 rows with values: (
    "<JUNENGINEDATA: 0x608000480eb0> (entity: ENGINEDATA; id: 0x40000b <x-coredata://10C884E2-18EF-4DA2-BC5D-4CBD0CE7D1A6/ENGINEDATA/p1> ; data: <fault>)",
    "<JUNENGINEDATA: 0x608000480f00> (entity: ENGINEDATA; id: 0x80000b <x-coredata://10C884E2-18EF-4DA2-BC5D-4CBD0CE7D1A6/ENGINEDATA/p2> ; data: <fault>)",
    "<JUNENGINEDATA: 0x608000480f50> (entity: ENGINEDATA; id: 0xc0000b <x-coredata://10C884E2-18EF-4DA2-BC5D-4CBD0CE7D1A6/ENGINEDATA/p3> ; data: <fault>)",
    ...
    "<JUNENGINEDATA: 0x600000288110> (entity: ENGINEDATA; id: 0x128c0000b <x-coredata://10C884E2-18EF-4DA2-BC5D-4CBD0CE7D1A6/ENGINEDATA/p1187> ; data: <fault>)",
    "<JUNENGINEDATA: 0x600000288160> (entity: ENGINEDATA; id: 0x12900000b <x-coredata://10C884E2-18EF-4DA2-BC5D-4CBD0CE7D1A6/ENGINEDATA/p1188> ; data: <fault>)",
    "<JUNENGINEDATA: 0x6000002881b0> (entity: ENGINEDATA; id: 0x12940000b <x-coredata://10C884E2-18EF-4DA2-BC5D-4CBD0CE7D1A6/ENGINEDATA/p1189> ; data: <fault>)"
)
CoreData: annotation: total fetch execution time: 0.1053s for 1185 rows.
2017-04-28 16:18:41.793201-0400 AppName[95979:11442649] Got results: 1185

좋은 소식은 모든 항목을 EngineData다시 만들 수 있다는 것입니다. 모든 EngineData개체를 일괄 삭제 하면 더 이상 충돌하지 않습니다 (새 개체를 만든 후에도). 가능하다면 문제의 원인을 이해하고 덜 과감한 해결책을 찾는 것이 좋습니다.

내가 발견 한 다른 몇 가지 사항은 다음과 같습니다.

  • 다른 컴퓨터에서 데이터베이스 복사를 시도했지만 해당 데이터를 사용하여 문제를 복제 할 수 없었습니다. 그 결과 데이터가 손상되었을 수 있다고 생각하게되었습니다.
  • 하지만 이전 버전의 앱과 해당 데이터로 돌아 가면 동일한 가져 오기가 제대로 작동합니다. 데이터 모델을 업그레이드하는 것 외에 다른 작업을 수행하지 않으면 동일한 예외가 발생합니다.
  • 관계에 대한 버전 해시 수정자를 설정해 보았습니다. Core Data가 마이그레이션 할 때 정리하도록 강제 할 수 있기를 바라지 만 운이 없습니다.
  • 배치 크기를 10으로 설정하면 예외 전에 900 개의 결과 (1185 개 중)를 반복 할 수 있습니다.
  • 이 프로세스를 사용하면 좋은 레코드를 한 번에 하나씩 삭제하여 문제가있는 레코드를 좁힐 수 있습니다. (삭제할 때마다 저장하고 추가 테스트를 위해 돌아 가야하는 경우 원본 데이터베이스의 백업을 유지했습니다.)
로봇 스페이서

많은 실험을 거쳐 범위를 좁힐 수있었습니다 . 더 이상 존재하지 않는 EngineData개체를 참조하는 Car개체가 몇 개 있습니다. 관계가 끊어져서 레코드가 새 데이터 모델 버전으로 올바르게 마이그레이션되지 않은 것 같습니다. .sqliteMac 앱 Base에서 파일을 열면 모든 좋은 레코드와 손상된 레코드 Z9_OBJECT10대해 설정된 필드를 볼 수 NULL있습니다.

원인을 찾았을 때 문제를 해결하는 것은 상당히 쉬웠습니다. 사용 NSBatchDeleteRequest하여 손상된 개체를 찾아 삭제할 수있었습니다.

do {
    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "EngineData")
    fetchRequest.predicate = NSPredicate(format: "object.uuid == nil")
    let batchRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
    try context.execute(batchRequest)
} catch {
    NSLog("Error deleting objects: \(error)")
}

내 술어에서는 object부모 개체 (이전에는 a Car, 이제는 a Vehicle)이며 uuid해당 개체의 선택적 속성이 아닙니다. 어트 리뷰 션이 선택 사항이 아닌 한 (손상되지 않은 개체에 대한 값 있음을 의미) 손상된 개체 만 성공적으로 삭제해야합니다.

여전히 손상된 개체를 가져 오기 때문에 예외가 발생할 것으로 예상 할 수 있습니다! 다행히 NSBatchDeleteRequest메모리에 아무것도로드하지 않고 저장소에서 직접 SQL 문을 실행하여 문제를 피할 수 있습니다.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

연관된 엔티티의 모든 행에 대한 핵심 데이터 술어

분류에서Dev

하나의 엔티티에서 여러 엔티티로의 핵심 데이터 관계

분류에서Dev

데이터를 업로드 한 후 엔티티는 어디에 있습니까?

분류에서Dev

iOS 핵심 데이터-비 선택에서 선택으로 관계 변경을위한 경량 마이그레이션

분류에서Dev

UITableView 행에 표시되는 핵심 데이터 엔티티 제한

분류에서Dev

상위 엔터티에 개체를 추가 할 때 중복을 만드는 핵심 데이터 대 다 관계

분류에서Dev

symfony2 / doctrine에 대한 기존 엔티티에 고유 한 토큰 열을 추가하기위한 적절한 마이그레이션 경로

분류에서Dev

핵심 데이터 엔티티 관계 계층

분류에서Dev

핵심 데이터 : 관련 엔티티의 속성을 기반으로 엔티티를 가져 오는 방법

분류에서Dev

핵심 데이터 관계 설계-원하는 엔티티 만로드

분류에서Dev

이진 데이터 개체를 핵심 데이터 엔터티로 마이그레이션

분류에서Dev

Microsoft Dynamics CRM 2015에서 데이터 마이그레이션을위한 약속 엔터티 매핑

분류에서Dev

엔터티 상태를 추가로 설정 한 후 Entity Framework Core가 데이터베이스 변경 사항을 저장하지 않음

분류에서Dev

자바 : 경계 내에서 한쪽에서 다른쪽으로 이동하는 엔티티

분류에서Dev

이 엔티티가 다른 테이블에서 참조되는 경우 부울로 표시하기 위해 Hibernate 엔티티에 필드를 추가하는 가장 깨끗한 방법

분류에서Dev

iOS 핵심 데이터-엔티티에 관련 데이터 추가

분류에서Dev

호텔에 대한 엔티티 관계 다이어그램

분류에서Dev

JPA에서 자식을 변경 한 후 부모 엔티티를 업데이트하는 방법은 무엇입니까?

분류에서Dev

Java에서 Restful 웹 서비스를위한 데이터 객체 (또는 엔티티) 생성

분류에서Dev

프로젝트에서 엔티티 프레임 워크에 사용한 적이있는 최대 엔티티 수?

분류에서Dev

프로젝트에서 엔티티 프레임 워크에 사용한 적이있는 최대 엔티티 수?

분류에서Dev

관계 1 : M으로 핵심 데이터 엔터티 레코드 표시

분류에서Dev

참조 엔터티를 업데이트 한 후 다른 엔터티에서 열을 업데이트 할 수있는 방법이 있습니까?

분류에서Dev

마법사를 사용하여 엔티티를 핵심 데이터에 저장

분류에서Dev

특정 관련 엔티티를 제외한 대다 관계에서 항목을 가져 오기위한 NSPredicate

분류에서Dev

핵심 데이터의 엔티티를 연결하는 방법

분류에서Dev

NHibernate : 지연로드없이 하나의 SQL 쿼리를 통해 하위 엔티티에 대한 필터를 사용하여 하위 엔티티를 열심히 가져 오는 방법은 무엇입니까?

분류에서Dev

단일 엔티티 편집 활동에서 단일 엔티티를로드하기위한 AsyncTaskLoader 대 AsyncTask?

분류에서Dev

관련 데이터로 엔티티 프레임 워크 핵심 데이터를 시드하는 방법

Related 관련 기사

  1. 1

    연관된 엔티티의 모든 행에 대한 핵심 데이터 술어

  2. 2

    하나의 엔티티에서 여러 엔티티로의 핵심 데이터 관계

  3. 3

    데이터를 업로드 한 후 엔티티는 어디에 있습니까?

  4. 4

    iOS 핵심 데이터-비 선택에서 선택으로 관계 변경을위한 경량 마이그레이션

  5. 5

    UITableView 행에 표시되는 핵심 데이터 엔티티 제한

  6. 6

    상위 엔터티에 개체를 추가 할 때 중복을 만드는 핵심 데이터 대 다 관계

  7. 7

    symfony2 / doctrine에 대한 기존 엔티티에 고유 한 토큰 열을 추가하기위한 적절한 마이그레이션 경로

  8. 8

    핵심 데이터 엔티티 관계 계층

  9. 9

    핵심 데이터 : 관련 엔티티의 속성을 기반으로 엔티티를 가져 오는 방법

  10. 10

    핵심 데이터 관계 설계-원하는 엔티티 만로드

  11. 11

    이진 데이터 개체를 핵심 데이터 엔터티로 마이그레이션

  12. 12

    Microsoft Dynamics CRM 2015에서 데이터 마이그레이션을위한 약속 엔터티 매핑

  13. 13

    엔터티 상태를 추가로 설정 한 후 Entity Framework Core가 데이터베이스 변경 사항을 저장하지 않음

  14. 14

    자바 : 경계 내에서 한쪽에서 다른쪽으로 이동하는 엔티티

  15. 15

    이 엔티티가 다른 테이블에서 참조되는 경우 부울로 표시하기 위해 Hibernate 엔티티에 필드를 추가하는 가장 깨끗한 방법

  16. 16

    iOS 핵심 데이터-엔티티에 관련 데이터 추가

  17. 17

    호텔에 대한 엔티티 관계 다이어그램

  18. 18

    JPA에서 자식을 변경 한 후 부모 엔티티를 업데이트하는 방법은 무엇입니까?

  19. 19

    Java에서 Restful 웹 서비스를위한 데이터 객체 (또는 엔티티) 생성

  20. 20

    프로젝트에서 엔티티 프레임 워크에 사용한 적이있는 최대 엔티티 수?

  21. 21

    프로젝트에서 엔티티 프레임 워크에 사용한 적이있는 최대 엔티티 수?

  22. 22

    관계 1 : M으로 핵심 데이터 엔터티 레코드 표시

  23. 23

    참조 엔터티를 업데이트 한 후 다른 엔터티에서 열을 업데이트 할 수있는 방법이 있습니까?

  24. 24

    마법사를 사용하여 엔티티를 핵심 데이터에 저장

  25. 25

    특정 관련 엔티티를 제외한 대다 관계에서 항목을 가져 오기위한 NSPredicate

  26. 26

    핵심 데이터의 엔티티를 연결하는 방법

  27. 27

    NHibernate : 지연로드없이 하나의 SQL 쿼리를 통해 하위 엔티티에 대한 필터를 사용하여 하위 엔티티를 열심히 가져 오는 방법은 무엇입니까?

  28. 28

    단일 엔티티 편집 활동에서 단일 엔티티를로드하기위한 AsyncTaskLoader 대 AsyncTask?

  29. 29

    관련 데이터로 엔티티 프레임 워크 핵심 데이터를 시드하는 방법

뜨겁다태그

보관