Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions build/azure-pipelines-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ schedules:
branches:
include:
- main
- dev-3.x

resources:
repositories:
Expand Down Expand Up @@ -70,10 +71,10 @@ extends:
versionSpec: '>=5.2.0'

- task: UseDotNet@2
displayName: Use .NET 8.0
displayName: Use .NET Core 10.x
inputs:
packageType: 'sdk'
version: '8.0.x'
version: 10.x
includePreviewVersions: true

- task: Powershell@2
displayName: 'Skip Strong Name Validation'
Expand All @@ -99,10 +100,10 @@ extends:
arguments: '--configuration $(buildConfiguration) --no-incremental'

- task: UseDotNet@2
displayName: Use .NET 3.x
displayName: Use .NET Core 10.x
inputs:
packageType: 'sdk'
version: '3.x'
version: 10.x
includePreviewVersions: true

- task: DotNetCoreCLI@2
displayName: 'Unit Tests (Microsoft.OData.ModelBuilder.Tests.csproj) '
Expand Down
14 changes: 8 additions & 6 deletions build/azure-pipelines-rolling.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ trigger:
include:
- main
- release-1.x
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should add dev-3.x rather replace release-1.x, just in case one was to create a pull request against the release-1.x branch

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is updated through commit 43762ce

- dev-3.x

# Pull request (PR) triggers
pr:
- main
- release-1.x
- dev-3.x

resources:
repositories:
Expand Down Expand Up @@ -66,10 +68,10 @@ extends:
checkLatest: true

- task: UseDotNet@2
displayName: Use .NET 8.0
displayName: Use .NET Core 10.x
inputs:
packageType: 'sdk'
version: '8.0.x'
version: 10.x
includePreviewVersions: true

- task: DotNetCoreCLI@2
displayName: 'Build Microsoft.OData.ModelBuilder.csproj '
Expand All @@ -84,10 +86,10 @@ extends:
arguments: '--configuration $(buildConfiguration) --no-incremental'

- task: UseDotNet@2
displayName: Use .NET 3.x
displayName: Use .NET Core 10.x
inputs:
packageType: 'sdk'
version: '3.x'
version: 10.x
includePreviewVersions: true

- task: DotNetCoreCLI@2
displayName: 'Unit Tests (Microsoft.OData.ModelBuilder.Tests.csproj) '
Expand Down
6 changes: 3 additions & 3 deletions build/builder.versions.settings.targets
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<Project>
<!-- Set the version number: major, minor, build and release (i.e. alpha, beta or blank for RTM)-->
<PropertyGroup>
<VersionMajor Condition="'$(VersionMajor)' == ''">2</VersionMajor>
<VersionMajor Condition="'$(VersionMajor)' == ''">3</VersionMajor>
<VersionMinor Condition="'$(VersionMinor)' == ''">0</VersionMinor>
<VersionBuild Condition="'$(VersionBuild)' == ''">0</VersionBuild>
<VersionRelease Condition="'$(VersionRelease)' == ''"></VersionRelease>
<VersionRelease Condition="'$(VersionRelease)' == ''">preview.1</VersionRelease>
</PropertyGroup>

<!-- For NuGet Package Dependencies -->
<PropertyGroup>
<ODataLibPackageDependency>[8.0.0, 9.0.0)</ODataLibPackageDependency>
<ODataLibPackageDependency>[9.0.0-preview.3, 10.0.0)</ODataLibPackageDependency>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious if this works

Copy link
Member Author

@WanjohiSammy WanjohiSammy Nov 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gathogojr This should work. It ensures the package uses ODL ≥ 9.0.0-preview.3 and < 10.0.0

Copy link
Member Author

@WanjohiSammy WanjohiSammy Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could bump the version in a different PR

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@WanjohiSammy I think the version is fine. What I was curious about is whether the part -preview.3 is evaluated as expected

<SystemComponentPackageDependency>[4.6.0,)</SystemComponentPackageDependency>
</PropertyGroup>

Expand Down
4 changes: 0 additions & 4 deletions src/Microsoft.OData.ModelBuilder/Commons/EdmLibHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,6 @@ internal static class EdmLibHelpers
new KeyValuePair<Type, IEdmPrimitiveType>(typeof(DateTimeOffset?), GetPrimitiveType(EdmPrimitiveTypeKind.DateTimeOffset)),
new KeyValuePair<Type, IEdmPrimitiveType>(typeof(TimeSpan), GetPrimitiveType(EdmPrimitiveTypeKind.Duration)),
new KeyValuePair<Type, IEdmPrimitiveType>(typeof(TimeSpan?), GetPrimitiveType(EdmPrimitiveTypeKind.Duration)),
new KeyValuePair<Type, IEdmPrimitiveType>(typeof(Date), GetPrimitiveType(EdmPrimitiveTypeKind.Date)),
new KeyValuePair<Type, IEdmPrimitiveType>(typeof(Date?), GetPrimitiveType(EdmPrimitiveTypeKind.Date)),
new KeyValuePair<Type, IEdmPrimitiveType>(typeof(TimeOfDay), GetPrimitiveType(EdmPrimitiveTypeKind.TimeOfDay)),
new KeyValuePair<Type, IEdmPrimitiveType>(typeof(TimeOfDay?), GetPrimitiveType(EdmPrimitiveTypeKind.TimeOfDay)),
new KeyValuePair<Type, IEdmPrimitiveType>(typeof(DateOnly), GetPrimitiveType(EdmPrimitiveTypeKind.Date)),
new KeyValuePair<Type, IEdmPrimitiveType>(typeof(DateOnly?), GetPrimitiveType(EdmPrimitiveTypeKind.Date)),
new KeyValuePair<Type, IEdmPrimitiveType>(typeof(TimeOnly), GetPrimitiveType(EdmPrimitiveTypeKind.TimeOfDay)),
Expand Down
13 changes: 12 additions & 1 deletion src/Microsoft.OData.ModelBuilder/Commons/TypeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ public static bool IsDateTime(Type clrType)
public static bool IsDateOnly(Type clrType)
{
Type underlyingTypeOrSelf = GetUnderlyingTypeOrSelf(clrType);
return underlyingTypeOrSelf.FullName == "System.DateOnly";
return underlyingTypeOrSelf == typeof(DateOnly);
}

/// <summary>
Expand All @@ -228,6 +228,17 @@ public static bool IsTimeSpan(Type clrType)
return underlyingTypeOrSelf == typeof(TimeSpan);
}

/// <summary>
/// Determine if a type is a TimeOnly.
/// </summary>
/// <param name="clrType">The type to test.</param>
/// <returns>True if the type is a TimeOnly; false otherwise.</returns>
public static bool IsTimeOnly(Type clrType)
{
Type underlyingTypeOrSelf = GetUnderlyingTypeOrSelf(clrType);
return underlyingTypeOrSelf == typeof(TimeOnly);
}

/// <summary>
/// Determine if a type is an enumeration.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ public override void Apply(PropertyConfiguration edmProperty, StructuralTypeConf
string typeName = columnAttribute.TypeName;
if (String.Compare(typeName, "date", StringComparison.OrdinalIgnoreCase) == 0)
{
primitiveProperty.AsDate();
primitiveProperty.AsDateOnly();
}
else if (String.Compare(typeName, "time", StringComparison.OrdinalIgnoreCase) == 0)
{
primitiveProperty.AsTimeOfDay();
primitiveProperty.AsTimeOnly();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@
<icon>images\odata.png</icon>
<repository type="git" url="https://github.com/OData/ModelBuilder.git" branch="master" />
<dependencies>
<group targetFramework=".NET8.0">
<group targetFramework=".NET10.0">
<dependency id="Microsoft.OData.Edm" version="$ODataLibPackageDependency$" />
<dependency id="Microsoft.Spatial" version="$ODataLibPackageDependency$" />
<dependency id="System.ComponentModel.Annotations" version="$SystemComponentPackageDependency$" />
</group>
</dependencies>
</metadata>
<files>
<file src="$ProductRoot$\net8.0\Microsoft.OData.ModelBuilder.dll" target="lib\net8.0" />
<file src="$ProductRoot$\net8.0\Microsoft.OData.ModelBuilder.xml" target="lib\net8.0" />
<file src="$ProductRoot$\net8.0\Microsoft.OData.ModelBuilder.pdb" target="lib\net8.0" />
<file src="$ProductRoot$\net10.0\Microsoft.OData.ModelBuilder.dll" target="lib\net10.0" />
<file src="$ProductRoot$\net10.0\Microsoft.OData.ModelBuilder.xml" target="lib\net10.0" />
<file src="$ProductRoot$\net10.0\Microsoft.OData.ModelBuilder.pdb" target="lib\net10.0" />
<file src="$SourcesRoot$\images\odata.png" target="images\" />
</files>
</package>
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@
<icon>images\odata.png</icon>
<repository type="git" url="https://github.com/OData/ModelBuilder.git" branch="master" />
<dependencies>
<group targetFramework=".NET8.0">
<group targetFramework=".NET10.0">
<dependency id="Microsoft.OData.Edm" version="$ODataLibPackageDependency$" />
<dependency id="Microsoft.Spatial" version="$ODataLibPackageDependency$" />
<dependency id="System.ComponentModel.Annotations" version="$SystemComponentPackageDependency$" />
</group>
</dependencies>
</metadata>
<files>
<file src="$ProductRoot$\net8.0\Microsoft.OData.ModelBuilder.dll" target="lib\net8.0" />
<file src="$ProductRoot$\net8.0\Microsoft.OData.ModelBuilder.xml" target="lib\net8.0" />
<file src="$ProductRoot$\net8.0\Microsoft.OData.ModelBuilder.pdb" target="lib\net8.0" />
<file src="$ProductRoot$\net10.0\Microsoft.OData.ModelBuilder.dll" target="lib\net10.0" />
<file src="$ProductRoot$\net10.0\Microsoft.OData.ModelBuilder.xml" target="lib\net10.0" />
<file src="$ProductRoot$\net10.0\Microsoft.OData.ModelBuilder.pdb" target="lib\net10.0" />
<file src="$SourcesRoot$\images\odata.png" target="images\" />
</files>
</package>
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
<TargetFramework>net10.0</TargetFramework>
<RootNamespace>Microsoft.OData.ModelBuilder</RootNamespace>
<DocumentationFile>$(OutputPath)$(AssemblyName).xml</DocumentationFile>
<PackageReadmeFile>README.md</PackageReadmeFile>
Expand All @@ -23,8 +23,8 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.OData.Edm" Version="8.0.1" />
<PackageReference Include="Microsoft.Spatial" Version="8.0.1" />
<PackageReference Include="Microsoft.OData.Edm" Version="9.0.0-preview.3" />
<PackageReference Include="Microsoft.Spatial" Version="9.0.0-preview.3" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.6.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
Expand Down
50 changes: 31 additions & 19 deletions src/Microsoft.OData.ModelBuilder/Microsoft.OData.ModelBuilder.xml
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,13 @@
<param name="clrType">The type to test.</param>
<returns>True if the type is a TimeSpan; false otherwise.</returns>
</member>
<member name="M:Microsoft.OData.ModelBuilder.TypeHelper.IsTimeOnly(System.Type)">
<summary>
Determine if a type is a TimeOnly.
</summary>
<param name="clrType">The type to test.</param>
<returns>True if the type is a TimeOnly; false otherwise.</returns>
</member>
<member name="M:Microsoft.OData.ModelBuilder.TypeHelper.IsEnum(System.Type)">
<summary>
Determine if a type is an enumeration.
Expand Down Expand Up @@ -3638,16 +3645,32 @@
</member>
<member name="M:Microsoft.OData.ModelBuilder.PrimitivePropertyConfigurationExtensions.AsDate(Microsoft.OData.ModelBuilder.PrimitivePropertyConfiguration)">
<summary>
If this primitive property is <see cref="T:System.DateTime"/>, this method will make the target
Edm type kind as <see cref="T:Microsoft.OData.Edm.Date"/>
If this primitive property is <see cref="T:System.DateTime"/> or <see cref="T:System.DateOnly"/>, this method will make the target
Edm type kind as <see cref="F:Microsoft.OData.Edm.EdmPrimitiveTypeKind.Date"/>
</summary>
<param name="property">Reference to the calling primitive property configuration.</param>
<returns>Returns itself so that multiple calls can be chained.</returns>
</member>
<member name="M:Microsoft.OData.ModelBuilder.PrimitivePropertyConfigurationExtensions.AsDateOnly(Microsoft.OData.ModelBuilder.PrimitivePropertyConfiguration)">
<summary>
If this primitive property is <see cref="T:System.DateTime"/> or <see cref="T:System.DateOnly"/>, this method will make the target
Edm type kind as <see cref="F:Microsoft.OData.Edm.EdmPrimitiveTypeKind.Date"/>
</summary>
<param name="property">Reference to the calling primitive property configuration.</param>
<returns>Returns itself so that multiple calls can be chained.</returns>
</member>
<member name="M:Microsoft.OData.ModelBuilder.PrimitivePropertyConfigurationExtensions.AsTimeOfDay(Microsoft.OData.ModelBuilder.PrimitivePropertyConfiguration)">
<summary>
If this primitive property is <see cref="T:System.TimeSpan"/>, this method will make the target
Edm type kind as <see cref="T:Microsoft.OData.Edm.TimeOfDay"/>
Edm type kind as <see cref="F:Microsoft.OData.Edm.EdmPrimitiveTypeKind.TimeOfDay"/>
</summary>
<param name="property">Reference to the calling primitive property configuration.</param>
<returns>Returns itself so that multiple calls can be chained.</returns>
</member>
<member name="M:Microsoft.OData.ModelBuilder.PrimitivePropertyConfigurationExtensions.AsTimeOnly(Microsoft.OData.ModelBuilder.PrimitivePropertyConfiguration)">
<summary>
If this primitive property is <see cref="T:System.TimeSpan"/> or <see cref="T:System.TimeOnly"/>, this method will make the target
Edm type kind as <see cref="F:Microsoft.OData.Edm.EdmPrimitiveTypeKind.TimeOfDay"/>
</summary>
<param name="property">Reference to the calling primitive property configuration.</param>
<returns>Returns itself so that multiple calls can be chained.</returns>
Expand Down Expand Up @@ -4327,6 +4350,11 @@
Looks up a localized string similar to The type &apos;{0}&apos; must be a primitive type..
</summary>
</member>
<member name="P:Microsoft.OData.ModelBuilder.SRResources.MustBeTimeOnlyProperty">
<summary>
Looks up a localized string similar to The property &apos;{0}&apos; on type &apos;{1}&apos; must be a System.TimeOnly property..
</summary>
</member>
<member name="P:Microsoft.OData.ModelBuilder.SRResources.MustBeTimeSpanProperty">
<summary>
Looks up a localized string similar to The property &apos;{0}&apos; on type &apos;{1}&apos; must be a System.TimeSpan property..
Expand Down Expand Up @@ -5340,22 +5368,6 @@
For example, in C# <c>t => t.MyProperty</c> and in Visual Basic .NET <c>Function(t) t.MyProperty</c>.</param>
<returns>A configuration object that can be used to further configure the property.</returns>
</member>
<member name="M:Microsoft.OData.ModelBuilder.StructuralTypeConfiguration`1.Property(System.Linq.Expressions.Expression{System.Func{`0,System.Nullable{Microsoft.OData.Edm.TimeOfDay}}})">
<summary>
Adds an time-of-day primitive property to the EDM type.
</summary>
<param name="propertyExpression">A lambda expression representing the navigation property for the relationship.
For example, in C# <c>t => t.MyProperty</c> and in Visual Basic .NET <c>Function(t) t.MyProperty</c>.</param>
<returns>A configuration object that can be used to further configure the property.</returns>
</member>
<member name="M:Microsoft.OData.ModelBuilder.StructuralTypeConfiguration`1.Property(System.Linq.Expressions.Expression{System.Func{`0,Microsoft.OData.Edm.TimeOfDay}})">
<summary>
Adds an time-of-day primitive property to the EDM type.
</summary>
<param name="propertyExpression">A lambda expression representing the navigation property for the relationship.
For example, in C# <c>t => t.MyProperty</c> and in Visual Basic .NET <c>Function(t) t.MyProperty</c>.</param>
<returns>A configuration object that can be used to further configure the property.</returns>
</member>
<member name="M:Microsoft.OData.ModelBuilder.StructuralTypeConfiguration`1.Property(System.Linq.Expressions.Expression{System.Func{`0,System.Nullable{System.TimeOnly}}})">
<summary>
Adds a <see cref="T:System.TimeOnly"/> primitive property to the EDM type.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,23 @@ namespace Microsoft.OData.ModelBuilder
public static class PrimitivePropertyConfigurationExtensions
{
/// <summary>
/// If this primitive property is <see cref="System.DateTime"/>, this method will make the target
/// Edm type kind as <see cref="Date"/>
/// If this primitive property is <see cref="System.DateTime"/> or <see cref="System.DateOnly"/>, this method will make the target
/// Edm type kind as <see cref="EdmPrimitiveTypeKind.Date"/>
/// </summary>
/// <param name="property">Reference to the calling primitive property configuration.</param>
/// <returns>Returns itself so that multiple calls can be chained.</returns>
public static PrimitivePropertyConfiguration AsDate(this PrimitivePropertyConfiguration property)
{
return property.AsDateOnly();
}

/// <summary>
/// If this primitive property is <see cref="System.DateTime"/> or <see cref="System.DateOnly"/>, this method will make the target
/// Edm type kind as <see cref="EdmPrimitiveTypeKind.Date"/>
/// </summary>
/// <param name="property">Reference to the calling primitive property configuration.</param>
/// <returns>Returns itself so that multiple calls can be chained.</returns>
public static PrimitivePropertyConfiguration AsDateOnly(this PrimitivePropertyConfiguration property)
{
if (property == null)
{
Expand All @@ -35,18 +46,29 @@ public static PrimitivePropertyConfiguration AsDate(this PrimitivePropertyConfig

/// <summary>
/// If this primitive property is <see cref="System.TimeSpan"/>, this method will make the target
/// Edm type kind as <see cref="TimeOfDay"/>
/// Edm type kind as <see cref="EdmPrimitiveTypeKind.TimeOfDay"/>
/// </summary>
/// <param name="property">Reference to the calling primitive property configuration.</param>
/// <returns>Returns itself so that multiple calls can be chained.</returns>
public static PrimitivePropertyConfiguration AsTimeOfDay(this PrimitivePropertyConfiguration property)
{
return property.AsTimeOnly();
}

/// <summary>
/// If this primitive property is <see cref="System.TimeSpan"/> or <see cref="System.TimeOnly"/>, this method will make the target
/// Edm type kind as <see cref="EdmPrimitiveTypeKind.TimeOfDay"/>
/// </summary>
/// <param name="property">Reference to the calling primitive property configuration.</param>
/// <returns>Returns itself so that multiple calls can be chained.</returns>
public static PrimitivePropertyConfiguration AsTimeOnly(this PrimitivePropertyConfiguration property)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, I'm a bit confused here. This method is named AsTimeOnly but inside the body, we only if the CLR type of the property is TimeSpan and throw an exception if it is not

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The AsDateOnly(...) extension method sets the property's target EDM type to EdmPrimitiveTypeKind.Date when the property is of type System.DateTime or System.DateOnly, ensuring the property is treated as a date in the OData metadata.

The AsTimeOnly(...) extension method sets the property's target EDM type to EdmPrimitiveTypeKind.TimeOfDay when the property is of type System.TimeSpan or System.TimeOnly.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@WanjohiSammy Why can't one of AsTimeOfDay and AsTimeOnly call the other instead of duplicating the code? Maybe AsTimeOfDay should call AsTimeOnly since AsTimeOfDay is what we might deprecate in the future?

Same argument around AsDate and AsDateOnly

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gathogojr This is updated with this commit b25d32e

{
if (property == null)
{
throw Error.ArgumentNull("property");
}

if (!TypeHelper.IsTimeSpan(property.RelatedClrType))
if (!TypeHelper.IsTimeSpan(property.RelatedClrType) && !TypeHelper.IsTimeOnly(property.RelatedClrType))
{
throw Error.Argument("property", SRResources.MustBeTimeSpanProperty, property.PropertyInfo.Name,
property.DeclaringType.FullName);
Expand Down
Loading