<!--
{
  "availability" : [
    "Xcode: 15.0.0 -",
    "iOS: 17.0.0 -",
    "macOS: 14.0.0 -",
    "tvOS: 17.0.0 -"
  ],
  "documentType" : "article",
  "framework" : "SwiftData",
  "identifier" : "/documentation/SwiftData/Defining-data-relationships-with-enumerations-and-model-classes",
  "metadataVersion" : "0.1.0",
  "role" : "sampleCode",
  "title" : "Defining data relationships with enumerations and model classes"
}
-->

# Defining data relationships with enumerations and model classes

Create relationships for static and dynamic data stored in your app.

## Overview

There are two ways to define data relationships in your app: using enumerations
and using the
[`Relationship(_:deleteRule:minimumModelCount:maximumModelCount:originalName:inverse:hashModifier:)`](/documentation/SwiftData/Relationship(_:deleteRule:minimumModelCount:maximumModelCount:originalName:inverse:hashModifier:))
macro in a model class. Which one to use depends on the unique circumstances of
your app. This article explains how to apply both approaches to the sample
<doc://com.apple.documentation/documentation/SwiftUI> app that persist data
using SwiftData.

### Relate a model class to static data

Enumerations are a convenient way to form relationships between a model class
and static data — data that the app defines and doesn’t change. To
define the static data, create an enumeration and ensure it conforms to the
<doc://com.apple.documentation/documentation/Swift/Codable> protocol. SwiftData
requires this conformance to persist any data that is of the enumeration type.
The following code, for example, declares a `Codable` conforming enumeration
that specify the animal type based on their diets:

```swift
extension Animal {
    enum Diet: String, CaseIterable, Codable {
        case herbivorous = "Herbivore"
        case carnivorous = "Carnivore"
        case omnivorous = "Omnivore"
    }
}
```

The `Animal` model class declares the property `diet` as a type of `Diet`.
Because this property is non-optional, its value must be set to one of the `Diet`
cases: `herbivore`, `carnivore`, and `ominvore`.

```swift
@Model
final class Animal {
    var name: String
    var diet: Diet
    var category: AnimalCategory?
    
    init(name: String, diet: Diet) {
        self.name = name
        self.diet = diet
    }
}
```

A person using the sample app can set the diet of an animal by choosing one of
the available `Diet` cases from a
<doc://com.apple.documentation/documentation/SwiftUI/Picker>; for example:

```swift
Picker("Diet", selection: $selectedDiet) {
    ForEach(Animal.Diet.allCases, id: \.self) { diet in
        Text(diet.rawValue).tag(diet)
    }
}
```

To learn more about how the sample app saves data changes, see
[Adding and editing persistent data in your app](/documentation/SwiftData/Adding-and-editing-persistent-data-in-your-app).

### Relate a model class to dynamic data

If the related data is dynamic and unknown to the app — data that
comes from an external source such as someone using the app or a remote server
— then form a relationship between two model classes instead of a class and
enumeration. For instance, the dynamic data in the sample app includes animals
and animal categories. An animal can belong to no more than one animal
category, and a category can contain zero, one, or more animals.

**iOS:**

![A screenshot of the sample app running in iOS, showing the list of animals that are in the mammal category.](images/com.apple.SwiftData/Defining-data-relationships-01~dark@2x.png)

**iPadOS:**

![A screenshot of the sample app running in iPadOS, showing a three-column user interface. The first column shows a list of categories with Mammal highlighted as the selected category. The second column shows the list of animals that are in the Mammal category. The third column shows an animal paw print icon. Under the icon is the text, Select an animal.](images/com.apple.SwiftData/Defining-data-relationships-02~dark@2x.png)

**macOS:**

![A screenshot of the sample app running in macOS, showing a three-column user interface. The first column shows a list of categories with Mammal highlighted as the selected category. The second column shows the list of animals that are in the Mammal category. The third column shows an animal paw print icon. Under the icon is the text, Select an animal.](images/com.apple.SwiftData/Defining-data-relationships-04~dark@2x.png)

**tvOS:**

![A screenshot of the sample app running in tvOS, showing the list of animals that are in the Mammal category. The first animal, cat, is highlighted.](images/com.apple.SwiftData/Defining-data-relationships-03~dark@2x.png)

To declare this relationship, the `AnimalCategory` class defines the property
`animals`, which represents the animals contained in the category. The class
also applies the
[`Relationship(_:deleteRule:minimumModelCount:maximumModelCount:originalName:inverse:hashModifier:)`](/documentation/SwiftData/Relationship(_:deleteRule:minimumModelCount:maximumModelCount:originalName:inverse:hashModifier:))
macro to the `animals` property. This macro defines the relationship between the
`AnimalCategory` and `Animal` model classes.

```swift
@Model
final class AnimalCategory {
    @Attribute(.unique) var name: String
    // `.cascade` tells SwiftData to delete all animals contained in the 
    // category when deleting it.
    @Relationship(deleteRule: .cascade, inverse: \Animal.category)
    var animals = [Animal]()
    
    init(name: String) {
        self.name = name
    }
}
```

Set the parameter values of this macro to configure the relationship. For
example, the `deleteRule` parameter specifies how SwiftData handles related
data during delete operations. The `inverse` parameter is a key path to the
store property, `category`, declared in the related model class, `Animal`. The
inverse parameter forms the relationship between the two classes,
`AnimalCategory` and `Animal`, and the `category` property declared in `Animal`
provides a reference to an animal category.

### Set a relationship’s delete rule

The `deleteRule` parameter specifies how SwiftData handles delete operations
with regards to the related data. The
[`Schema.Relationship.DeleteRule.cascade`](/documentation/SwiftData/Schema/Relationship/DeleteRule-swift.enum/cascade) delete rule tells
SwiftData to delete all related data when deleting the primary object. For
example, deleting an `AnimalCategory` in the sample app causes SwiftData to
also delete all animals contained in that category.

```swift
@Relationship(deleteRule: .cascade, inverse: \Animal.category)
var animals = [Animal]()
```

If you don’t want to delete the animals within a category, you can use the
[`Schema.Relationship.DeleteRule.nullify`](/documentation/SwiftData/Schema/Relationship/DeleteRule-swift.enum/nullify) delete rule. This rule
tells SwiftData to set the animal’s `category` property to `nil` for each
animal contained in the animal category when deleting the category. Because the
default value for the `deleteRule` parameter is `nullify`, you can create the
relationship without explicitly specifying the delete rule, like so:

```swift
@Relationship(inverse: \Animal.category)
var animals = [Animal]()
```

For a complete list of delete rules, see
[`Schema.Relationship.DeleteRule`](/documentation/SwiftData/Schema/Relationship/DeleteRule-swift.enum).

### Create a model container

Whether your data model includes relationships, you must always create a
model container for your app when using SwiftData. The sample app creates a
model container using the
<doc://com.apple.documentation/documentation/SwiftUI/View/modelContainer(for:inMemory:isAutosaveEnabled:isUndoEnabled:onSetup:)-18hhy>
modifier, passing in the model type `AnimalCategory.self`:

```swift
@main
struct SwiftDataAnimalsApp: App {
    var body: some Scene {
        WindowGroup() {
            ContentView()
        }
        .modelContainer(for: AnimalCategory.self)
    }
}
```

SwiftData uses the model type to construct the schema that determines the
structure of the persistent storage area. The schema also includes all related
types that form the object graph of the provided model type. For instance,
`AnimalCategory` is a root model type of an object graph. `AnimalCategory`
contains a relationship to the model type `Animal`, which means that the schema
includes `Animal` along with `AnimalCategory`. If `Animal` had a relationship
to another model type, the schema would also include that type.

If your app defines multiple root model types, use the  <doc://com.apple.documentation/documentation/SwiftUI/View/modelContainer(for:inMemory:isAutosaveEnabled:isUndoEnabled:onSetup:)-8oc48>
modifier, passing in an array that contains each root model type used in your
app.

---

Copyright &copy; 2026 Apple Inc. All rights reserved. | [Terms of Use](https://www.apple.com/legal/internet-services/terms/site.html) | [Privacy Policy](https://www.apple.com/privacy/privacy-policy)