Skip to content

[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]:

cs
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; }
}
anchor

In this example:

  • CustomerWithAddress has a [DataSubjectId] on Id and a [PersonalData] field Name.
  • HomeAddress is marked with [DeepPersonalData], so Tayra recurses into the Address object.
  • The Address class has three [PersonalData] fields: Street, City, and PostalCode.
  • 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:

  1. The parent entity's [DataSubjectId] is used to look up or create the encryption key.
  2. All [PersonalData] fields in the nested object are encrypted with that same key.
  3. 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:

csharp
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:

PropertyTypeDefaultDescription
Scopestring?nullAn 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:

csharp
var customer = new CustomerWithAddress
{
    Id = Guid.NewGuid(),
    Name = "Jane",
    HomeAddress = null, // Skipped during encryption
};

await fieldEncrypter.EncryptAsync(customer); // Only Name is encrypted

See Also