Thursday, September 11, 2025

EF Core 10.0: Support for Complex Types without using Owned Entities

EF Core 10.0 introduces a new approach for mapping complex types in a Entity. Prior to EF Core 10.0, we can manage complex types using Owned Entities.

With EF Core 10.0, we now have a new method ComplexProperty() and in this post let's have a look at the newer approach and possibly do a comparison.

Consider the following.

public class Customer
{
    public int Id { getset}

    public string Name { getset}

    public required Address ShippingAddress { getset}

    public required Address BillingAddress { getset}
}

public class Address
{
    public required string Street { getset}

    public required string City { getset}

    public required string State { getset}

    public required string PostalCode { getset}
}

Now let's see how we can map ShippingAddress and BillingAddress, using Owned Entities vs ComplexProperty.

public class MyDbContext : DbContext
{
    public DbSet<Customer> Customers { getset}

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder
            .UseSqlServer("<ConnectionString>");
    }

    override protected void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder
            .Entity<Customer>(x =>
            {
                // Using Owned Entity Types
                x.OwnsOne(x => x.ShippingAddress);

                // Using Complex Types (new in EF Core 10)
                x.ComplexProperty(x => x.BillingAddress);
            });
    }
}

Owned Entity vs ComplexProperty
You can basically do all the customizations as we used to do in Owned Entities. 

For an example, map the properties to different column names, I can do this.

override protected void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<Customer>(x =>
        {
            // Using Owned Entity Types
            x.OwnsOne(x => x.ShippingAddress, y =>
            {
                // Map the properties to different column names
                y.Property(p => p.Street).HasColumnName("ShippingStreet");
            });

            // Using Complex Types(new in EF Core 10)
            x.ComplexProperty(x => x.BillingAddress, y =>
            {
                // Map the properties to different column names
                y.Property(p => p.Street).HasColumnName("BillingStreet");
            });
        });
}

From EF Core 10.0 onwards, ComplexProperty() would be more recommended approach for managing complex types.

Read more:
   EF Core 10.0: Complex Types

Hope this helps.

Happy Coding.

Regards,
Jaliya

Wednesday, September 10, 2025

Announcing Visual Studio 2026: Insiders

Just a few hours ago, the first Public Preview of the next version of Visual Studio is announced along with .NET 10 RC 1. It's Visual Studio 2026 or Visual Studio 18 under the classic versioning system. 
Visual Studio 2026: Insiders
This new release brings significant performance improvements and of course a host of exciting new features.

One of the standout updates is the introduction of the Insiders channel, which replaces the traditional Preview channel from earlier versions of Visual Studio.

There's a lot to explore, and it's available now. Try it out today!


Happy Coding.

Regards,
Jaliya

Thursday, September 4, 2025

ASP.NET Core 10.0: Custom Validation Support for Minimal APIs

In a previous post, I wrote about ASP.NET Core 10.0: Validation Support for Minimal APIs. In this post, let's go a bit further and see how we can implement custom validations using both ValidationAttribute implementations and implementing the IValidatableObject interface.

ValidationAttribute 


With ValidationAttribute, we can create a Custom attribute with our own custom logic.
public class CustomEmptyValidationAttribute : ValidationAttribute
{
    protected override ValidationResultIsValid(objectvalueValidationContext _)
    {
        if (value is string str && string.IsNullOrEmpty(str))
        {
            return new ValidationResult("Value cannot be null or empty.");
        }

        return ValidationResult.Success;
    }
}
And then we can apply the attribute, something like below for an example.
internal record Employee([CustomEmptyValidation] string Name);

IValidatableObject 


A class/record can implement IValidatableObject and add the validation logic. The validation will kick in as part of model binding.
internal record Employee : IValidatableObject
{
    [Range(1, int.MaxValue)]
    public int Id { getset}

    public string Name { getset}

    public IEnumerable<ValidationResult> Validate(ValidationContext _)
    {
        if (string.IsNullOrEmpty(Name))
        {
            yield return new ValidationResult("Name cannot be null or empty."[nameof(Name)]);
        }
    }
}
Note: Currently there is a bug where IValidatableObject wouldn't trigger validation when there is no validation attribute on a property. (aspnetcore/issues/63394: ASP.NET Core 10.0: Built-in Validation with IValidatableObject)

Hope this helps.

Happy Coding.

Regards,
Jaliya