[DeepPersonalData]
The [DeepPersonalData] attribute marks a property that holds a nested object containing [PersonalData] fields. Tayra will recursively process the nested object, encrypting and decrypting its personal data fields using the parent entity's encryption key.
Basic Usage
Apply [DeepPersonalData] to a class-type property. The nested class uses [PersonalData] on its own fields, but does not need its own [DataSubjectId]:
public class Address
{
[PersonalData]
public string Street { get; set; } = "";
[PersonalData]
public string City { get; set; } = "";
[PersonalData]
public string PostalCode { get; set; } = "";
}
public class CustomerWithAddress
{
[DataSubjectId]
public Guid Id { get; set; }
[PersonalData]
public string Name { get; set; } = "";
[DeepPersonalData]
public Address? HomeAddress { get; set; }
}In this example:
CustomerWithAddresshas a[DataSubjectId]onIdand a[PersonalData]fieldName.HomeAddressis marked with[DeepPersonalData], so Tayra recurses into theAddressobject.- The
Addressclass has three[PersonalData]fields:Street,City, andPostalCode. - All fields -- both on the parent and the nested object -- are encrypted with the same key derived from
Id.
Parent Key Inheritance
When a nested object does not have its own [DataSubjectId], it inherits the encryption key from its parent entity. This means:
- The parent entity's
[DataSubjectId]is used to look up or create the encryption key. - All
[PersonalData]fields in the nested object are encrypted with that same key. - Crypto-shredding the parent's key destroys both the parent's and the nested object's personal data.
If the nested object does have its own [DataSubjectId], it uses its own independent key instead.
When to Use Independent Keys
Give nested objects their own [DataSubjectId] when they represent a different data subject. For example, an Order might have a [DataSubjectId] for the customer, while a nested DeliveryDriver object has its own [DataSubjectId] -- shredding the customer's key should not affect the driver's data.
Collections
[DeepPersonalData] also works on collections of objects. If the property type is a List<T>, T[], or any type implementing IList<T>, Tayra iterates through each element and processes it:
public class CustomerWithAddresses
{
[DataSubjectId]
public Guid Id { get; set; }
[DeepPersonalData]
public List<Address>? Addresses { get; set; }
}Each Address in the list will have its [PersonalData] fields encrypted using the parent's key.
Scope Property
The [DeepPersonalData] attribute has an optional Scope property:
| Property | Type | Default | Description |
|---|---|---|---|
Scope | string? | null | An optional scope identifier for the nested data. Reserved for future use in scoped metadata resolution. |
Null Handling
If the [DeepPersonalData] property is null, Tayra skips it without error. This is safe:
var customer = new CustomerWithAddress
{
Id = Guid.NewGuid(),
Name = "Jane",
HomeAddress = null, // Skipped during encryption
};
await fieldEncrypter.EncryptAsync(customer); // Only Name is encryptedSee Also
[PersonalData]-- Marking individual fields for encryption[DataSubjectId]-- Key derivation and grouping[SerializedPersonalData]-- Non-string type encryption- Attributes Overview -- All four attributes at a glance
