Search code examples
c#reflectionentity-framework-core

How to handle OwnsOne and OwnsMany entities in EF Core 8 with reflection


I want to add shadow properties to all entities.

What I did is to add shadow properties to the parent class (entity). For this purpose I have written the following code in my DbContext:

var entityTypes = builder.Model.GetEntityTypes()
        .Where(e => typeof(Entity).IsAssignableFrom(e.ClrType)
                    && e.ClrType != typeof(Entity));

foreach (var entityType in entityTypes)
{
    builder.Entity(entityType.ClrType)
            .Property<DateTime>("CreatedDate")
            .HasDefaultValueSql("GETUTCDATE()");

    builder.Entity(entityType.ClrType)
            .Property<DateTime?>("UpdatedDate")
            .HasConversion(new ValueConverter<DateTime, DateTime>(v => v.ToUniversalTime(),
                    v => DateTime.SpecifyKind(v, DateTimeKind.Utc)))
            .ValueGeneratedOnUpdate();
}

But the problem is that it affects entities that are OwnsOne or OwnsMany:

Unable to create a 'DbContext' of type 'ContentCommandDbContext'. The exception 'The entity type 'Comment' cannot be configured as non-owned because it has already been configured as a owned. Use the nested builder in OwnsOne or OwnsMany on the owner entity type builder to further configure this type. If you want to override previous configuration first remove the entity type from the model by calling 'Ignore'. See https://aka.ms/efcore-docs-owned for more information and examples.' was thrown while attempting to create an instance. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728

To avoid this error, I need to identify the entities that are OwnsOne or OwnsMany and not put them in this code.I can do this using hard code, for example:

var entityTypes = builder.Model.GetEntityTypes()
    .Where(e => typeof(Entity).IsAssignableFrom(e.ClrType) && e.ClrType != typeof(Entity) && e.ClrType != typeof(Comment));

And it works fine, but it becomes problematic during development (we all know). Can this be done using reflection? I am new to reflection.


Solution

  • No reflection is needed, the information is provided by EF Core metadata API, in this case by the IReadOnlyEntityType.IsOwned method, e.g.

    var entityTypes = builder.Model.GetEntityTypes()
        .Where(e => !e.IsOwned() && ...);