[SwiftUI] CoreDataRelationships

Woozoo·2023년 2월 16일
0

[SwiftUI Review]

목록 보기
4/41
post-custom-banner

CoreData RelationShips

relationship... 정말 헷갈리는 부분이지만
그만큼 CoreData에서 중요한 부분이기도 함!

코어데이터 설명 읽어보기!
마음 단단히 먹구!
코딩시작

뷰모델을 우선 선언해줌



다음은 CoreData를 관리하는 객체를 싱글톤으로 만들어줄겨

이제 CoreData를 실제로 다뤄야하니까 import CoreData 해줬다
container랑 이 안에 존재하는 context를 상수로 선언해줌


초기값을 따로 안넣었으니까 init이 필요하겠죠

전이랑 다르게 context에 container.viewContext를 저장해주네

save 메소드도 하나 필요할 것 같음


아아 context.save()로 쉽게 쓸라고 한거구나
container.viewContext.save()를 조금 더 보기 쉽게할라고

CoreDataManager구성은 우선 마쳤고
viewModel로 돌아와서 방금 만든 매니저를 선언해주자

CoreDataContainer 라는 이름의 DataModel파일 작성!

3개의 entity를 만들어줄거임

BusinessEntity, DepartmentEntity, EmployeeEntity
이렇게 3가지

비즈니스 안에는 부서가 있을거고, 이 부서들 안에는 직원들이 있을 예정

비즈니스Entity에 name attribute를 구성하고,
부서Entity에 name attribute를 구성했다

두개를 연결해주자!
비즈니스Entity Relationships에departments라는 관계를 만들어줌



Destination은 관계의 방향에서 목적지, inverse는 어떤 관계랑 연결이 될지를 나타냄


Inspector창을 열면 Type항목이 있는데 하나로 대응될 지 여러개로 대응될지 정해줄 수 있음

원래는 하나의 비즈니스에선 여러개의 부서를 가지고
각각의 부서들은 그 상위의 비즈니스랑만 연결이 될텐데


지금 같은 경우엔 하나의 부서가 여러개의 비즈니스랑 대응될 수도 있을 거잖음
그래서 To Many로 골라줬음 (이건 개발자의 몫인거. 어떻게 관계를 맺을지는 온전히 나의 상황에 맞추면됨)


EmployeeEntity도 만들어줌! 나이랑 언제 출근시작했는지, 이름 같은 attribute를 만들어줬음

이번엔 이 직원들은 각각 하나 비즈니스랑 대응되는 관계 하나, 부서랑 대응되는 관계 하나로만 가능하게 해줬음
직원이 몸이 여러개도 아니고 출근을 여기저기 몸 담을 순 없잖음

비즈니스Entity에선 여러 갈래의 직원들이 있을거니까 many로 대응 되게 해줌


옼께이
부서도 마찬가지로 여러명의 직원들이 있을테니까 To Many로 대응되게 해줌

참 옛날처럼 editor모드 바꾸는 건 없어짐!
관계 설정끝!


다시 뷰모델 작성한 곳으로 돌아와서

@Published로 [BusinessEntity] 배열을 만들어줌
그리고 addBusiness 메소드를 구성해줄거임

manager에서 save로 context를 저장했던걸 다시 save()라는 메소드로 만들고
addBusiness에 추가해줌

간단한 뷰를 구성해주고

실행!

잘 실행됨

이제 저장된 Business Entity를 가져와봅시다

뷰모델에서 작성해준 getBusiness

struct BusinessView: View {
    
    let entity: BusinessEntity
    
    var body: some View {
        VStack(alignment: .leading, spacing: 20) {
            Text("Name: \(entity.name ?? "")")
                .bold()
            if let departments = entity.departments?.allObjects as? [DepartmentEntity] {
                Text("Departments:")
                    .bold()
                ForEach(departments) { department in
                    Text(department.name ?? "")
                }
            }
            
            if let employees = entity.employees?.allObjects as? [EmployeeEntity] {
                Text("Employees:")
                    .bold()
                ForEach(employees) { employee in
                    Text(employee.name ?? "")
                }
            }
        }
        .padding()
        .frame(maxWidth: 300, alignment: .leading)
        .background(Color.gray.opacity(0.5))
        .cornerRadius(10)
        .shadow(radius: 10)
    }
}

그리고 BusinessView를 구성해줬다
여서 보면 BusinessEntity안엔 departments랑 employees가 다 있음
entity.departments는 set라서 array로 바꿔주기 위해선 allObjects로 [Any]타입의 array를 만든 다음에 [DepartmentsEntyty] 타입으로 캐스팅해줘야함

employees도 마찬가지!

이제 만들어준 BusinessView를 원래의 뷰에서 horizontal ScrollView안에 ForEach로 돌려보자

save가 호출될 때 getBusinesses도 같이 호출되어야 뷰가 업뎃 됨


그리고 business가 add 될 때 departments랑 employees도 업뎃 되어야함

    func addBusiness() {
        let newBusiness = BusinessEntity(context: manager.context)
        newBusiness.name = "Apple"

        
        // add existing departments to the new business
        //newBusiness.departments = []
        
        // add existing employees to the new business
        //newBusiness.employees = []
        
        // add new business to existing department
        //newBusiness.addToDepartments(<#T##value: DepartmentEntity##DepartmentEntity#>)
        
        // add new business to existing employee
        //newBusiness.addToEmployees(<#T##value: EmployeeEntity##EmployeeEntity#>)
        save()
    }


department를 추가해주는 메소드를 작성하고

기존에 cta Button로직을 vm.addDepartment로 바꿔줌

글고 지금 누적된거 지워줄라고 save될 때 기존의 businesses 안에 담긴 배열 싹 지우고
dispatchQueue.main.asyncAfter로 살짝 딜레이 줘서 save되게 해줌


DepartmentView도 만들었다!
BusinessView 그대로 복사하고
살짝 수정해줌

struct DepartmentView: View {
    
    let entity: DepartmentEntity
    
    var body: some View {
        VStack(alignment: .leading, spacing: 20) {
            Text("Name: \(entity.name ?? "")")
                .bold()
            if let businesses = entity.businesses?.allObjects as? [BusinessEntity] {
                Text("Businesses:")
                    .bold()
                ForEach(businesses) { business in
                    Text(business.name ?? "")
                }
            }
            
            if let employees = entity.employees?.allObjects as? [EmployeeEntity] {
                Text("Employees:")
                    .bold()
                ForEach(employees) { employee in
                    Text(employee.name ?? "")
                }
            }
        }
        .padding()
        .frame(maxWidth: 300, alignment: .leading)
        .background(Color.green.opacity(0.5))
        .cornerRadius(10)
        .shadow(radius: 10)
    }
}

bootcamp뷰에서
비즈니스 뷰 스크롤로 보이는 거 밑에
departments 뷰도 그려줄 거

vm 에 새로운 [DepartmentEntity] 배열이 필요하겠죠

구성해주고, getDepartments() 만들고 init 될 때 실행되게 해줌

save메소드에도 한번 removeall한 다음에 getDepartments로 업뎃 될 수 있게 해주고


새로운 Entity를 생성해주게 되면 Attribute말고도 relationship도 설정해줄 수 있다
기존에 있던 Entity에 추가해주는 것도 가능하고 새로운 Entity에 붙여주는 건 가능함

이제 Employee를 추가해봅시다



다른 business나 department 지정하지 않은채로 그냥 직원만 만드는 것도 가능함


sort 하는법

get할 때


fetchRequest를 할 때 sort 해주면 됨

filter는 predicate 추가하면되고


delet하는 과정에서 관계에 있는 다른 entity를 어떻게 처리할지 정해줄 수 있음

default는 nullify인데 다른 애는 남겨두는 형태로 지워짐
casacade는 관계에 있는 다른 entity도 다 지움
deny는 다른 관계의 entity가 존재한다면 안 지워짐


profile
우주형
post-custom-banner

0개의 댓글