Save SwiftData object for model with one to many relationship

First the Model: import Foundation import SwiftData //Model for Earned Value Analysis @Model final class CostReport{ var aCWP: Double //Actual Cost of Work Performed var bCWP: Double //Budgeted Cost of Work Performed var bCWS: Double // Budgeted Cost of Work Scheduled var cumACWP: Double// Cumlative Actual Cost of Work Performed var cumBCWP: Double // Cumlative Budgeted Cost of Work Performed var cumBCWS: Double // Cumlative Budgeted Cost of Work Scheduled var startDateOfPeriod: Date var endDateOfPeriod: Date var contract: Contract? init(aCWP: Double = 0.0, bCWP: Double = 0.0, bCWS: Double = 0.0, cumACWP: Double = 0.0, cumBCWP: Double = 0.0, cumBCWS: Double = 0.0, startDateOfPeriod: Date = .now, endDateOfPeriod: Date = .now, contract: Contract) { self.aCWP = aCWP self.bCWP = bCWP self.bCWS = bCWS self.cumACWP = cumACWP self.cumBCWP = cumBCWP self.cumBCWS = cumBCWS self.startDateOfPeriod = startDateOfPeriod self.endDateOfPeriod = endDateOfPeriod self.contract = contract } } @Model //Model for Contracts final class Contract{ var costReports: [CostReport] var contractType: ContractType? @Attribute(.unique)var contractNumber: String @Attribute(.unique)var contractName: String var startDate: Date var endDate: Date var contractValue: Double var contractorName: String var contractorContact: String var contractorPhone: String var contractorEmail: String init(costReports: [CostReport], contractType: ContractType, contractNumber: String = "", contractName: String = "", startDate: Date = .now, endDate: Date = .now, contractValue: Double = 0.0, contractorName: String = "", contractorContact: String = "", contractorPhone: String = "", contractorEmail: String = "") { self.costReports = costReports self.contractType = contractType self.contractNumber = contractNumber self.contractName = contractName self.startDate = startDate self.endDate = endDate self.contractValue = contractValue self.contractorName = contractorName self.contractorContact = contractorContact self.contractorPhone = contractorPhone self.contractorEmail = contractorEmail } } @Model //Model for contract types final class ContractType{ var contracts: [Contract] @Attribute(.unique)var typeName: String @Attribute(.unique)var typeCode: String var typeDescription: String init(contracts: [Contract], typeName: String = "", typeCode: String = "", typeDescription: String = "") { self.contracts = contracts self.typeName = typeName self.typeCode = typeCode self.typeDescription = typeDescription } } ContractType has a one to many relationship to Contract. Contract has a one to many relationship with CostReport. The ContractTypes can vary depending on the users situation so I need the user to be able to enter ContractTypes.

Code for that: import SwiftUI import SwiftData

struct EnterContractTypes: View { @Environment(.modelContext) var managedObjectContext @Query private var contracts: [Contract] @Query private var contractTypes: [ContractType] @State private var typeName: String = "" @State private var typeCode: String = "" @State private var typeDescription: String = "" var body: some View { Form { Section(header: Text("Enter Contract Type") .foregroundStyle(Color(.green)) .bold() .font(.largeTitle)) { TextField("Name", text: $typeName) .frame(width: 400, height: 40) TextField("Code", text: $typeCode) .frame(width: 400, height: 40) TextField("Description", text: $typeDescription, axis: .vertical) .frame(width: 600, height: 60) } } .frame(width:1000, height:500) } func save() { let newContractType = ContractType(context: managedObjectContext) newContractType.typeName = typeName newContractType.typeCode = typeCode newContractType.typeDescription = typeDescription try? managedObjectContext.save()

The "let newContractType = ContractType(context: managedObjectContext)" is where the error happens. It says there is an extra argument in the context call.

Answered by captchoas in 857965022

Found the issue: In a one to many relationship to be able to enter the one side of the relationship you need to identify the many side, even if you are not entering any values for the many side.

In this case the many side is Contracts and a state variable needs to be declared @State private var contracts: [Contract] = [] with an empty array.

This is the most unreadable/least readable post I've ever seen on these forums.

PLEASE use the code formatting options when you make a post.

May I suggest you reply to this thread with the code properly formatted so we can read it? We might be able to help you out then.

import SwiftData
//Model for Earned Value Analysis
The Model
@Model
final class CostReport{
    var aCWP: Double //Actual Cost of Work Performed
    var bCWP: Double //Budgeted Cost of Work Performed
    var bCWS: Double // Budgeted Cost of Work Scheduled
    var cumACWP: Double// Cumlative Actual Cost of Work Performed
    var cumBCWP: Double // Cumlative Budgeted Cost of Work Performed
    var cumBCWS: Double // Cumlative Budgeted Cost of Work Scheduled
    var startDateOfPeriod: Date
    var endDateOfPeriod: Date
    var contract: Contract?
    init(aCWP: Double = 0.0, bCWP: Double = 0.0, bCWS: Double = 0.0, cumACWP: Double = 0.0, cumBCWP: Double = 0.0, cumBCWS: Double = 0.0, startDateOfPeriod: Date = .now, endDateOfPeriod: Date = .now, contract: Contract) {
        self.aCWP = aCWP
        self.bCWP = bCWP
        self.bCWS = bCWS
        self.cumACWP = cumACWP
        self.cumBCWP = cumBCWP
        self.cumBCWS = cumBCWS
        self.startDateOfPeriod = startDateOfPeriod
        self.endDateOfPeriod = endDateOfPeriod
        self.contract = contract
    }
}
@Model //Model for Contracts
final class Contract{
    var costReports: [CostReport]
    var contractType: ContractType?
    @Attribute(.unique)var contractNumber: String
    @Attribute(.unique)var contractName: String
    var startDate: Date
    var endDate: Date
    var contractValue: Double
    var contractorName: String
    var contractorContact: String
    var contractorPhone: String
    var contractorEmail: String
    init(costReports: [CostReport], contractType: ContractType, contractNumber: String = "", contractName: String = "", startDate: Date = .now, endDate: Date = .now, contractValue: Double = 0.0, contractorName: String = "", contractorContact: String = "", contractorPhone: String = "", contractorEmail: String = "") {
        self.costReports = costReports
        self.contractType = contractType
        self.contractNumber = contractNumber
        self.contractName = contractName
        self.startDate = startDate
        self.endDate = endDate
        self.contractValue = contractValue
        self.contractorName = contractorName
        self.contractorContact = contractorContact
        self.contractorPhone = contractorPhone
        self.contractorEmail = contractorEmail
    }
}
@Model //Model for contract types
final class ContractType{
    var contracts: [Contract]
    @Attribute(.unique)var typeName: String
    @Attribute(.unique)var typeCode: String
    var typeDescription: String
    init(contracts: [Contract], typeName: String = "", typeCode: String = "", typeDescription: String = "") {
        self.contracts = contracts
        self.typeName = typeName
        self.typeCode = typeCode
        self.typeDescription = typeDescription
    }
}

The swiftui code for user entry:

```import SwiftUI
import SwiftData

struct EnterContractTypes: View {
    @Environment(\.modelContext) var managedObjectContext
    @Query private var contracts: [Contract]
    @Query private var contractTypes: [ContractType]
    @State private var typeName: String = ""
    @State private var typeCode: String = ""
    @State private var typeDescription: String = ""
    var body: some View {
        Form {
            Section(header: Text("Enter Contract Type")
                .foregroundStyle(Color(.green))
                    .bold()
                .font(.largeTitle)) {
                    TextField("Name", text: $typeName)
                        .frame(width: 400, height: 40)
                    TextField("Code", text: $typeCode)
                        .frame(width: 400, height: 40)
                    TextField("Description", text: $typeDescription, axis: .vertical)
                        .frame(width: 600, height: 60)
                }
        }
        .frame(width:1000, height:500)
    }
}

Last post used code block but appears to have failed.  I did not check it because I was in a hurry, sorry.


OOPS! forgot the save function

        let contractType = ContractType()
        contractType.typeName = typeName
        contractType.typeCode = typeCode
        contractType.typeDescription = typeDescription
        modelContext.insert(contractType)
        try? modelContext.save()
    }
}
Accepted Answer

Found the issue: In a one to many relationship to be able to enter the one side of the relationship you need to identify the many side, even if you are not entering any values for the many side.

In this case the many side is Contracts and a state variable needs to be declared @State private var contracts: [Contract] = [] with an empty array.

Save SwiftData object for model with one to many relationship
 
 
Q