Skip to content

Commit

Permalink
Add OData to Linq support with the OData2Linq project (#1)
Browse files Browse the repository at this point in the history
* Add OData2Linq project
* Add test and benchmark projects
* Add extension methods and unit tests from the Community.OData.Linq nuget
  • Loading branch information
ArnaudB88 authored Feb 17, 2025
1 parent 40caec2 commit 829d7e8
Show file tree
Hide file tree
Showing 51 changed files with 3,092 additions and 2 deletions.
107 changes: 107 additions & 0 deletions .github/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
[![NuGet Version](https://img.shields.io/nuget/v/OData2Linq?label=NuGet)](https://www.nuget.org/packages/OData2Linq/)

# OData2Linq
Apply an OData text query (filter, order by, select, ..) to an IQueryable expression.

# Features
- Manipulate an IQueryable expression with OData text query

## Supported OData parameters
| Params | In Memory Collections | Entity Framework | CosmosDB SQL API |
| ------------- |:---------------------:|:----------------:| :---------------:|
| $filter |+ | + | + |
| $orderby |+ | + | + |
| $select |+ | + | - |
| $expand |+ | + | - |
| $top |+ | + | + |
| $skip |+ | + | + |

# Samples
Please check samples below to get started

## .NET Fiddle
https://dotnetfiddle.net/6dLB2g

## Console app
```csharp
using System;
using System.Linq;
using OData2Linq;

public class Entity
{
public int Id { get; set; }
public string Name { get; set; }
}

public static class GetStartedDemo
{
public static void Demo()
{
Entity[] items =
{
new Entity { Id = 1, Name = "n1" },
new Entity { Id = 2, Name = "n2" },
new Entity { Id = 3, Name = "n3" }
};
IQueryable<Entity> query = items.AsQueryable();

var result = query.OData().Filter("Id eq 1 or Name eq 'n3'").OrderBy("Name desc").TopSkip("10", "0").ToArray();

// Id: 3 Name: n3
// Id: 1 Name: n1
foreach (Entity entity in result)
{
Console.WriteLine("Id: {0} Name: {1}", entity.Id, entity.Name);
}
}
}
```

## Support ToArrayAsync(), ToListAsync(), and all other provider specific methods.
Use `.ToOriginalQuery()` after finishing working with OData to be able to support provider specific methods of original query.

### Entity Framework async data fetch.
```
Student[] array = await dbContext.Students.OData()
.Filter("LastName eq 'Alexander' or FirstMidName eq 'Laura'")
.OrderBy("EnrollmentDate desc")
.TopSkip("1","1")
.ToOriginalQuery() // required to be able to use .ToArrayAsync() next.
.ToArrayAsync();
ISelectExpandWrapper[] select2 = await dbContext.Students.OData()
.Filter("LastName eq 'Alexander' or FirstMidName eq 'Laura'")
.OrderBy("EnrollmentDate desc")
.SelectExpandAsQueryable("LastName", "Enrollments($select=CourseId)") //.SelectExpandAsQueryable() use .ToOriginalQuery() implicitly, so not need to call it.
.ToArrayAsync()
```
### CosmosDb SQL API async data fetch.
```
var item = await Container.GetItemLinqQueryable<TestEntity>().OData()
.Filter($"Id eq '{id1}'")
.TopSkip("1")
.ToOriginalQuery() // required to be able to use .ToFeedIterator() next.
.ToFeedIterator()
.ReadNextAsync()
```

## Advanced code samples at wiki
See the [Wiki pages](https://github.com/ArnaudB88/OData2Linq/wiki)

# Contribution
Please feel free to create issues and pull requests to the main branch.

# Nuget
| Package | NuGet | Info |
|---------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------|------------------|
| OData2Linq | [![NuGet Version](https://img.shields.io/nuget/v/OData2Linq?label=NuGet)](https://www.nuget.org/packages/OData2Linq/) | OData v8 support |
| Community.OData.Linq.Json | [![NuGet Version](https://img.shields.io/nuget/v/Community.OData.Linq.Json)](https://www.nuget.org/packages/Community.OData.Linq.Json) | Still works on odata v7 libraries. Open an issue to create a new package for odata v8. |
| Community.OData.Linq.AspNetCore | [![NuGet Version](https://img.shields.io/nuget/v/Community.OData.Linq.AspNetCore)](https://www.nuget.org/packages/Community.OData.Linq.AspNetCore) | Still works on odata v7 libraries. Open an issue to create a new package for odata v8. |

# References
This project is based on the following project:
https://github.com/IharYakimush/comminity-data-odata-linq

The repository is a fork from:
https://github.com/OData/AspNetCoreOData
34 changes: 34 additions & 0 deletions .github/workflows/odata2linq-cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# This workflow will build a .NET project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net

name: odata2linq-cd

on:
push:
tags:
- 'OData2Linq_*.*.*'

jobs:
build:

runs-on: windows-latest
strategy:
matrix:
dotnet-version: ['6.0.x']

steps:
- uses: actions/checkout@v4
- name: Setup dotnet ${{ matrix.dotnet-version }}
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ matrix.dotnet-version }}
- name: Restore dependencies
run: dotnet restore ./AspNetCoreOData.sln
- name: Build
run: dotnet build ./AspNetCoreOData.sln -c Release --no-restore
- name: Test
run: dotnet test ./AspNetCoreOData.sln -c Release --no-build --verbosity normal
- name: Pack
run: dotnet pack ./src/OData2Linq/OData2Linq.csproj -c Release -o .\artifacts --no-build
- name: Publish to NuGet
run: dotnet nuget push .\artifacts\*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }}
31 changes: 31 additions & 0 deletions .github/workflows/odata2linq-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# This workflow will build a .NET project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net

name: odata2linq-ci

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

jobs:
build:

runs-on: windows-latest
strategy:
matrix:
dotnet-version: ['6.0.x']

steps:
- uses: actions/checkout@v4
- name: Setup dotnet ${{ matrix.dotnet-version }}
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ matrix.dotnet-version }}
- name: Restore dependencies
run: dotnet restore ./AspNetCoreOData.sln
- name: Build
run: dotnet build ./AspNetCoreOData.sln --no-restore
- name: Test
run: dotnet test ./AspNetCoreOData.sln --no-build --verbosity normal
23 changes: 22 additions & 1 deletion AspNetCoreOData.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.3.32901.215
VisualStudioVersion = 17.12.35707.178
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{2F0E102B-EB33-4025-BE56-7B8F9D2C4B8A}"
EndProject
Expand All @@ -19,6 +19,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.OData.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.OData.TestCommon", "test\Microsoft.AspNetCore.OData.TestCommon\Microsoft.AspNetCore.OData.TestCommon.csproj", "{9DB7ACCB-79CC-495C-A145-BC50A7733A21}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OData2Linq", "src\OData2Linq\OData2Linq.csproj", "{568A35C2-8677-41C6-9098-3AEF23286A9E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OData2Linq.Tests", "test\OData2Linq.Tests\OData2Linq.Tests.csproj", "{E7F48129-7544-4D85-ABE1-4CB037E1C780}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OData2Linq.Benchmark", "test\OData2Linq.Benchmark\OData2Linq.Benchmark.csproj", "{11B8ED5C-E54C-46A4-A5A7-E880E5EC634E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ODataCustomizedSample", "sample\ODataCustomizedSample\ODataCustomizedSample.csproj", "{BDC5474B-9511-4CDF-83FE-376C7130F7F0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ODataDynamicModel", "sample\ODataDynamicModel\ODataDynamicModel.csproj", "{CE04E38B-547F-46C0-ABE4-F981E3A1874F}"
Expand Down Expand Up @@ -55,6 +61,18 @@ Global
{9DB7ACCB-79CC-495C-A145-BC50A7733A21}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9DB7ACCB-79CC-495C-A145-BC50A7733A21}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9DB7ACCB-79CC-495C-A145-BC50A7733A21}.Release|Any CPU.Build.0 = Release|Any CPU
{568A35C2-8677-41C6-9098-3AEF23286A9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{568A35C2-8677-41C6-9098-3AEF23286A9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{568A35C2-8677-41C6-9098-3AEF23286A9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{568A35C2-8677-41C6-9098-3AEF23286A9E}.Release|Any CPU.Build.0 = Release|Any CPU
{E7F48129-7544-4D85-ABE1-4CB037E1C780}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E7F48129-7544-4D85-ABE1-4CB037E1C780}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E7F48129-7544-4D85-ABE1-4CB037E1C780}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E7F48129-7544-4D85-ABE1-4CB037E1C780}.Release|Any CPU.Build.0 = Release|Any CPU
{11B8ED5C-E54C-46A4-A5A7-E880E5EC634E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{11B8ED5C-E54C-46A4-A5A7-E880E5EC634E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{11B8ED5C-E54C-46A4-A5A7-E880E5EC634E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{11B8ED5C-E54C-46A4-A5A7-E880E5EC634E}.Release|Any CPU.Build.0 = Release|Any CPU
{BDC5474B-9511-4CDF-83FE-376C7130F7F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BDC5474B-9511-4CDF-83FE-376C7130F7F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BDC5474B-9511-4CDF-83FE-376C7130F7F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down Expand Up @@ -85,6 +103,9 @@ Global
{FF17DFD5-7ED0-433F-8DD9-4576E0CFFFBA} = {F994C269-55BA-44F0-9DA7-6D5A3CFA79EB}
{E428817E-A93C-4C1F-9D20-F5CA8C3627C1} = {F994C269-55BA-44F0-9DA7-6D5A3CFA79EB}
{9DB7ACCB-79CC-495C-A145-BC50A7733A21} = {F994C269-55BA-44F0-9DA7-6D5A3CFA79EB}
{568A35C2-8677-41C6-9098-3AEF23286A9E} = {2F0E102B-EB33-4025-BE56-7B8F9D2C4B8A}
{E7F48129-7544-4D85-ABE1-4CB037E1C780} = {F994C269-55BA-44F0-9DA7-6D5A3CFA79EB}
{11B8ED5C-E54C-46A4-A5A7-E880E5EC634E} = {F994C269-55BA-44F0-9DA7-6D5A3CFA79EB}
{BDC5474B-9511-4CDF-83FE-376C7130F7F0} = {B1F86961-6958-4617-ACA4-C231F95AE099}
{CE04E38B-547F-46C0-ABE4-F981E3A1874F} = {B1F86961-6958-4617-ACA4-C231F95AE099}
{647EFCFA-55A7-4F0A-AD40-4B6EB1BFCFFA} = {B1F86961-6958-4617-ACA4-C231F95AE099}
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# ASP.NET Core OData
---

For the OData2Linq readme, [click here](https://github.com/ArnaudB88/OData2Linq).

---

Component | Build | Status
--------|--------- |---------
ASP.NET Core OData|Rolling | [![Build Status](https://identitydivision.visualstudio.com/OData/_apis/build/status%2FAspNetCoreOData%2FAspNetCoreOData-main-rolling-1ES?repoName=OData%2FAspNetCoreOData&branchName=main)](https://identitydivision.visualstudio.com/OData/_build/latest?definitionId=2403&repoName=OData%2FAspNetCoreOData&branchName=main)
Expand Down
2 changes: 2 additions & 0 deletions src/Microsoft.AspNetCore.OData/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.OData.E2E.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]

[assembly: InternalsVisibleTo("Microsoft.AspNetCore.OData.NewtonsoftJson.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]

[assembly: InternalsVisibleTo(assemblyName: "OData2Linq, PublicKey=00240000048000009400000006020000002400005253413100040000010001009d992fba5d4cbb3d67a46a65d01094fac14c4d8269c76dfe22a2447b37ed7339fb906d08d84a44bd8fe496bdab1a4d49c0a5df61600349d7a4708da1df0e4e22e726d830957a8ab2aba161633728e45561b078ee89c5c5afef23379499bee69c0b70e8039d09f11d0817e65cfd3848f2a6a2db0e75e767f596ff28d25c8acadb")]
Binary file added src/OData2Linq/FriendAssemblies.snk
Binary file not shown.
Loading

0 comments on commit 829d7e8

Please sign in to comment.