In this post we will explore the concept of Shadow Properties.

We will look into why we might need shadow properties, what they are exayctly and how we can accomplish creating them with ef core.

What are Shadow Properties And Why do we need them?

Shadow properties are nothing but hidden properties.
Hidden here means they are hidden from the business model and the application/business layer the app resides in.
They still do exist in the database though.

In other words:
A Shadow Property has a field/column in a database table but is not (directlyaccessable from the model class.
This means you cannot access them by the dot operator or have them as properties on your models.

But why though?

We need shadow properties to keep models clean from metadata that is not useful for the domain itself, but makes sense from a reporting perspective.

Some database fields suitable for shadow properties:

  • CreatedAt
  • UpdatedAt
  • UpdatedBy
  • Foreign keys
    (hiding can make sense as it is only a database related concept;
    in other cases it might make sense to have them to help the querying of related data by Id)
  • In general all the  database related properties
    RowId, ConcurrencyStamp and so on are candidates to be implemented as shadow properties

    How do we use shadow properties

Shadow properties are by definition not on the model.
So we cannot add them to the class directly. (Or if we have already we should remove them again, see the revert a migration post on how to do this).

Because of this we only can add shadow properties via the fluent API.
We will demonstrate it with the CreatedAt property.

To do this we must follow this steps:

  1. Access the Entity Set on the builder with the generic EntityType to be changed
  2. Add a Property of the DataType you want it to be and specifiy the name of the database field as a string
  3. Generate a SQL default value by invoking a SQL method.We do this by adding to the  OnModelCreating method of the used DbContext :
°
builder.Entity<MyEntity>()
    .Property<DateTime>("CreatedAt")
    .HasDefaultValueSql("getdate()");
°

After this create a migration with

°
dotnet ef migrations add AddedShadowProperty -c MyContext 
°

And then update the database

°
dotnet ef database update
°

Access shadow properties nonetheless

But what if you absolutely positively have to access the shadow property for one reason or another?

Now the field will be available in the database, but not on the model.
The question is can we still access the Shadow property albeit not in a direct way?

Of course we can, to get access to a shadow property, you can query it with the same name you created it with:

// access to a shadow property
var entities = context.MyEntities.ToList();
var filteredForToday = entities.FindAll(x => 
{
    var b = context.Entry(x).Property<DateTime>("CreatedAt").CurrentValue;
    return b.Date.Equals(DateTime.Now.Date);
};

 

Categories: Relations

0 Comments

Leave a Reply

Avatar placeholder