November 26th, 2025
0 reactions

Announcing OData Model Builder 3.0.0 Preview 1 Release

We’re excited to announce that OData Model Builder 3.0.0 Preview 1 has been officially released and is available on NuGet:

This is a major release that brings the library up to date with the latest .NET and OData ecosystem, featuring .NET 10 support, OData Library 9.x compatibility, and modernized date/time handling using native .NET types.

What’s New in OData Model Builder 3.0.0 Preview 1

Framework & Dependency Updates

.NET 10 Support

OData Model Builder now targets .NET 10, aligning with the latest .NET runtime and taking advantage of modern performance improvements and language features. The library has moved from net8.0 to net10.0 as its target framework.

OData Library 9.x Integration

This release updates all OData dependencies from version 8.0.x to 9.0.0-preview.3, ensuring full compatibility with the latest OData .NET (ODL) ecosystem:

  • Microsoft.OData.Edm: 8.0.1 → 9.0.0-preview.3
  • Microsoft.Spatial: 8.0.1 → 9.0.0-preview.3

The integration includes adapting to OData Library 9.x API changes, such as the removal of the CsdlTarget parameter from CSDL writer methods. This simplifies CSDL generation and aligns with OData Library’s focus on OData CSDL exclusively (Entity Framework CSDL is no longer supported in the modern .NET Core/EF Core ecosystem).

Breaking Changes: Modernized Date and Time Handling

Use System.DateOnly and System.TimeOnly

The most significant change in this release is the complete migration from legacy EDM date/time types to .NET’s native date and time types. This brings OData Model Builder in line with modern .NET standards and improves consistency across the framework.

What’s Changed:

  • Removed: Support for Microsoft.OData.Edm.Date and Microsoft.OData.Edm.TimeOfDay
  • Added: Full support for System.DateOnly and System.TimeOnly

Specific Changes:

  1. Type Mappings Removed from EdmLibHelpers:
// Removed:
typeof(Date) → EdmPrimitiveTypeKind.Date
typeof(TimeOfDay) → EdmPrimitiveTypeKind.TimeOfDay

// Now using native .NET types:
typeof(DateOnly) → EdmPrimitiveTypeKind.Date
typeof(TimeOnly) → EdmPrimitiveTypeKind.TimeOfDay
  1. Property Configuration Methods Removed from StructuralTypeConfiguration<T>:
    • Property() overloads for TimeOfDay and Date types are no longer available
    • Use the standard Property() method with DateOnly and TimeOnly instead

Migration Guidance

If you’re upgrading from OData Model Builder 2.x, you’ll need to update your code:

Before (2.x):

using Microsoft.OData.Edm;

public class Event
{
    public Date EventDate { get; set; }
    public TimeOfDay StartTime { get; set; }
}

After (3.0):

public class Event
{
    public DateOnly EventDate { get; set; }
    public TimeOnly StartTime { get; set; }
}

Configuration Updates:

All model configurations using Date or TimeOfDay properties need to be updated to use DateOnly and TimeOnly. The API surface is otherwise identical.

New Features

Enhanced TimeOnly Support

To provide feature parity with existing date/time handling, we’ve added new extension methods and helpers:

  1. AsTimeOnly() Extension Method for PrimitivePropertyConfiguration:
    • Complements the existing AsTimeOfDay() method
    • Provides explicit configuration for TimeOnly properties
    • Used internally by conventions like ColumnAttributeEdmPropertyConvention
  2. IsTimeOnly() Helper Method in TypeHelper:
    • Enables type detection for TimeOnly properties
    • Matches the pattern of existing type helpers like IsDateOnly(), IsDateTime(), etc.

Example Usage:

var builder = new ODataConventionModelBuilder();
builder.EntityType<Event>()
    .Property(e => e.StartTime)
    .AsTimeOnly();

Why These Changes Matter

Alignment with Modern .NET

By adopting DateOnly and TimeOnly, OData Model Builder leverages types that are:

  • Native to .NET: No need for custom EDM-specific types
  • Well-documented: Full framework support and documentation
  • Consistent: Same types used across .NET applications
  • Performant: Optimized by the .NET runtime

OData Spec Compliance

DateOnly and TimeOnly naturally align with the OData specification’s dateValue and timeOfDayValue requirements, ensuring protocol compliance:

Ecosystem Integration

This release ensures OData Model Builder works seamlessly with:

  • OData Library 9.x: Full compatibility with the latest OData .NET stack
  • .NET 10: Access to the latest runtime improvements and features

Summary

OData Model Builder 3.0.0 Preview 1 represents a significant step forward for the library:

  • Modern .NET alignment: Full .NET 10 support with native DateOnly/TimeOnly types
  • Breaking changes for long-term benefit: Removal of legacy EDM date/time types simplifies the API and improves maintainability
  • OData 9.x compatibility: Seamless integration with the latest OData ecosystem

Getting Started

Install the preview package from NuGet:

dotnet add package Microsoft.OData.ModelBuilder --version 3.0.0-preview.1

Or add it directly to your .csproj file:

<PackageReference Include="Microsoft.OData.ModelBuilder" Version="3.0.0-preview.1" />

Quick Start Example

Here’s a complete example showing how to use the new DateOnly and TimeOnly types:

Step 1: Define your entity model

public class Event
{
    public int Id { get; set; }
    public string Title { get; set; }
    public DateOnly EventDate { get; set; }
    public TimeOnly StartTime { get; set; }
    public TimeOnly EndTime { get; set; }
    public string Location { get; set; }
}

Step 2: Build the OData model

using Microsoft.OData.ModelBuilder;

var builder = new ODataConventionModelBuilder();
builder.EntitySet<Event>("Events");

var model = builder.GetEdmModel();

Step 3: View the generated CSDL

The model builder will generate CSDL that properly maps DateOnly to Edm.Date and TimeOnly to Edm.TimeOfDay:

<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
  <edmx:DataServices>
    <Schema Namespace="Default" xmlns="http://docs.oasis-open.org/odata/ns/edm">
      <EntityType Name="Event">
        <Key>
          <PropertyRef Name="Id" />
        </Key>
        <Property Name="Id" Type="Edm.Int32" Nullable="false" />
        <Property Name="Title" Type="Edm.String" />
        <Property Name="EventDate" Type="Edm.Date" Nullable="false" />
        <Property Name="StartTime" Type="Edm.TimeOfDay" Nullable="false" />
        <Property Name="EndTime" Type="Edm.TimeOfDay" Nullable="false" />
      </EntityType>
      <EntityContainer Name="Container">
        <EntitySet Name="Events" EntityType="Default.Event" />
      </EntityContainer>
    </Schema>
  </edmx:DataServices>
</edmx:Edmx>

Complete working example:

using Microsoft.OData.ModelBuilder;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
using System.Xml;

// Define the entity
public class Event
{
    public int Id { get; set; }
    public string Title { get; set; }
    public DateOnly EventDate { get; set; }
    public TimeOnly StartTime { get; set; }
    public TimeOnly EndTime { get; set; }
}

// Build the model
var builder = new ODataConventionModelBuilder();
builder.EntitySet<Event>("Events");
IEdmModel model = builder.GetEdmModel();

// Write out the CSDL
using var sw = new StringWriter();
using var xw = XmlWriter.Create(sw, new XmlWriterSettings { Indent = true });
CsdlWriter.TryWriteCsdl(model, xw, out var errors);
xw.Flush();

Console.WriteLine(sw.ToString());

This example demonstrates the seamless integration of .NET’s native date and time types with OData’s EDM model, making it easier than ever to build type-safe OData services.

Feedback

This is a preview release, and we welcome your feedback! Please try the package and share your experiences on the GitHub repository.

As we work toward the final 3.0.0 release, your input will help us ensure a smooth transition for the OData Model Builder community.

Category
ODataODL

0 comments