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
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ public IActionResult Post([FromBody]Customer c)
}

// Alternate key: SSN
[HttpGet("odata/Customers(SSN={ssn})")]
[HttpGet("odata/Customers(SSN={ssn})")] // use community alternate key
[HttpGet("odata/Customers(CoreSN={ssn})")] // use core alternate key
public IActionResult GetCustomerBySSN(string ssn)
{
var c = _repository.GetCustomers().FirstOrDefault(c => c.SSN == ssn);
Expand All @@ -62,7 +63,8 @@ public IActionResult GetCustomerBySSN(string ssn)
return Ok(c);
}

[HttpPatch("odata/Customers(SSN={ssnKey})")]
[HttpPatch("odata/Customers(SSN={ssnKey})")] // use community alternate key
[HttpPatch("odata/Customers(CoreSN={ssnKey})")] // use core alternate key
public IActionResult PatchCustomerBySSN(string ssnKey, Delta<Customer> delta)
{
var originalCustomer = _repository.GetCustomers().FirstOrDefault(c => c.SSN == ssnKey);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ public IActionResult Get(int key)
}

// alternate key: Name
[HttpGet("odata/Orders(Name={orderName})")]
[HttpGet("odata/Orders(Name={orderName})")] // use community alternate key
[HttpGet("odata/Orders(CoreName={orderName})")] // use core alternate key
public IActionResult GetOrderByName(string orderName)
{
var c = _repository.GetOrders().FirstOrDefault(c => c.Name == orderName);
Expand All @@ -55,7 +56,8 @@ public IActionResult GetOrderByName(string orderName)
}

// alternate key: Token
[HttpGet("odata/Orders(Token={token})")]
[HttpGet("odata/Orders(Token={token})")] // use community alternate key
[HttpGet("odata/Orders(CoreToken={token})")] // use core alternate key
public IActionResult GetOrderByToken(Guid token)
{
var c = _repository.GetOrders().FirstOrDefault(c => c.Token == token);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ public IActionResult Get(int key)
return Ok(c);
}

[HttpGet("odata/People(c_or_r={cr},passport={passport})")]
[HttpGet("odata/People(c_or_r={cr},passport={passport})")] // use community alternate key
[HttpGet("odata/People(core_c_r={cr},core_passport={passport})")] // use core alternate key
public IActionResult FindPeopleByCountryAndPassport(string cr, string passport)
{
var c = _repository.GetPeople().FirstOrDefault(c => c.CountryOrRegion == cr && c.Passport == passport);
Expand Down
48 changes: 18 additions & 30 deletions sample/ODataAlternateKeySample/Models/EdmModelBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
//------------------------------------------------------------------------------

using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OData.ModelBuilder;

namespace ODataAlternateKeySample.Models
Expand Down Expand Up @@ -38,6 +40,13 @@ private static void SetCustomerAlternateKey(EdmModel model)
{
{"SSN", ssn}
});

// Use Core Vocabulary version.
model.AddAlternateKeyAnnotation(customer, new Dictionary<string, IEdmProperty>()
{
{"CoreSN", ssn}
},
true /*true means to use core.alternatekeys term*/);
}

private static void SetOrderAlternateKey(EdmModel model)
Expand All @@ -58,15 +67,14 @@ private static void SetOrderAlternateKey(EdmModel model)
{"Token", token},
});

// ODL doesn't support Org.OData.Core.V1.AlternateKeys to do the uri parsing
/*
// Use the APIs to build the core alternate keys
var alternateKeysCollection = new List<IEdmExpression>();
foreach (string item in new [] { "Name", "Token"})
{
List<IEdmExpression> propertyRefs = new List<IEdmExpression>();

IEdmRecordExpression propertyRef = new EdmRecordExpression(
new EdmPropertyConstructor("Alias", new EdmStringConstant(item)),
new EdmPropertyConstructor("Alias", new EdmStringConstant($"Core{item}")),
new EdmPropertyConstructor("Name", new EdmPropertyPathExpression(item)));
propertyRefs.Add(propertyRef);

Expand All @@ -81,7 +89,6 @@ private static void SetOrderAlternateKey(EdmModel model)

annotation.SetSerializationLocation(model, EdmVocabularyAnnotationSerializationLocation.Inline);
model.SetVocabularyAnnotation(annotation);
*/
}

private static void SetPersonAlternateKey(EdmModel model)
Expand All @@ -98,32 +105,13 @@ private static void SetPersonAlternateKey(EdmModel model)
{"passport", passport},
});

// ODL doesn't support Org.OData.Core.V1.AlternateKeys to do the uri parsing
/*
List<IEdmExpression> propertyRefs = new List<IEdmExpression>();

IEdmRecordExpression propertyRef = new EdmRecordExpression(
new EdmPropertyConstructor("Alias", new EdmStringConstant("CountryOrRegion")),
new EdmPropertyConstructor("Name", new EdmPropertyPathExpression("CountryOrRegion")));
propertyRefs.Add(propertyRef);

propertyRef = new EdmRecordExpression(
new EdmPropertyConstructor("Alias", new EdmStringConstant("Passport")),
new EdmPropertyConstructor("Name", new EdmPropertyPathExpression("Passport")));
propertyRefs.Add(propertyRef);

EdmRecordExpression alternateKeyRecord = new EdmRecordExpression(
new EdmPropertyConstructor("Key", new EdmCollectionExpression(propertyRefs)));

var alternateKeysCollection = new List<IEdmExpression>();
alternateKeysCollection.Add(alternateKeyRecord);

var term = model.FindTerm("Org.OData.Core.V1.AlternateKeys");
var annotation = new EdmVocabularyAnnotation(person, term, new EdmCollectionExpression(alternateKeysCollection));

annotation.SetSerializationLocation(model, EdmVocabularyAnnotationSerializationLocation.Inline);
model.SetVocabularyAnnotation(annotation);
*/
// Use Core Vocabulary version.
model.AddAlternateKeyAnnotation(person, new Dictionary<string, IEdmProperty>
{
{"core_c_r", cr},
{"core_passport", passport},
},
true);
}
}
}
100 changes: 88 additions & 12 deletions sample/ODataAlternateKeySample/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,32 @@ This sample illustrates how to use the Alternate key in ASP.NET Core OData 8.x.

Alternate key is an 'alternate' key compared to the declared key.

You can use `Org.OData.Core.V1.AlternateKey` term to define the alternate key vocabulary annotation, that's the recommended way.

For backward compatible, it also supports `OData.Community.Keys.V1.AlternateKeys` alternate key term.

For example, any customer can have a `Id` as his declared key, meanwhile, he can also have `SSN` as his identity.

The sample implements three alternate key scenarios:

1. Single alternate key
- Using declared keys : ~/odata/Customers(3)
- Using alternate keys: ~/odata/Customer(SSN='SSN-3-103')
- Using community alternate keys: ~/odata/Customers(SSN='SSN-3-103')
- Using core alternate keys: ~/odata/Customers(CoreSN='SSN-3-103')

2. Multiple alternate keys
- Using declared keys : ~/odata/Orders(2)
- Using alternate keys: ~/odata/Orders(Name='Order-2')
- Using alternate keys: ~/odata/Orders(Token=75036B94-C836-4946-8CC8-054CF54060EC)
- Using community alternate keys: ~/odata/Orders(Name='Order-2')
- Using community alternate keys: ~/odata/Orders(Token=75036B94-C836-4946-8CC8-054CF54060EC)
- Using core alternate keys: ~/odata/Orders(CoreName='Order-2')
- Using core alternate keys: ~/odata/Orders(CoreToken=75036B94-C836-4946-8CC8-054CF54060EC)

3. Composition alternate keys
- Using declared keys : ~/odata/People(2)
- Using alternate keys: ~/odata/People(CountryOrRegion='USA',Passport='9999')
- Using community alternate keys: ~/odata/People(c_or_r='USA',passport='9999')
- Using core keys: ~/odata/People(core_c_r='USA',core_passport='9999')

You may noticed that you should use the `alternateKeyAlias=alternateKeyValue` pattern to invoke the API.
You may notice that we should use the `alternateKeyAlias=alternateKeyValue` pattern to invoke the API. It's only supported using attribute routing.

## Verify the Model

Expand All @@ -32,9 +40,9 @@ Send `GET http://localhost:5219/odata/$metadata`

You can get the following metadata.

1) <strong>Customer</strong> type has `OData.Community.Keys.V1.AlternateKeys` annotation with one alternate key
2) <strong>Order</strong> type has `OData.Community.Keys.V1.AlternateKeys` annotation with two alternate keys
3) <strong>Person</strong> type has `OData.Community.Keys.V1.AlternateKeys` annotation with one alternate key, in which has two records
1) <strong>Customer</strong> type has `OData.Community.Keys.V1.AlternateKeys` and `Org.OData.Core.V1.AlternateKey` annotation with one alternate key
2) <strong>Order</strong> type has `OData.Community.Keys.V1.AlternateKeys` and `Org.OData.Core.V1.AlternateKey` annotation with two alternate keys
3) <strong>Person</strong> type has `OData.Community.Keys.V1.AlternateKeys` and `Org.OData.Core.V1.AlternateKey` annotation with one composite alternate key

```xml
<?xml version="1.0" encoding="utf-8"?>
Expand All @@ -48,6 +56,7 @@ You can get the following metadata.
<Property Name="Id" Type="Edm.Int32" Nullable="false" />
<Property Name="Name" Type="Edm.String" />
<Property Name="SSN" Type="Edm.String" />
<Property Name="Titles" Type="Collection(Edm.String)" />
<Annotation Term="OData.Community.Keys.V1.AlternateKeys">
<Collection>
<Record Type="OData.Community.Keys.V1.AlternateKey">
Expand All @@ -62,6 +71,20 @@ You can get the following metadata.
</Record>
</Collection>
</Annotation>
<Annotation Term="Org.OData.Core.V1.AlternateKeys">
<Collection>
<Record Type="Org.OData.Core.V1.AlternateKey">
<PropertyValue Property="Key">
<Collection>
<Record Type="Org.OData.Core.V1.PropertyRef">
<PropertyValue Property="Alias" String="CoreSN" />
<PropertyValue Property="Name" PropertyPath="SSN" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</Annotation>
</EntityType>
<EntityType Name="Order">
<Key>
Expand All @@ -70,7 +93,7 @@ You can get the following metadata.
<Property Name="Id" Type="Edm.Int32" Nullable="false" />
<Property Name="Name" Type="Edm.String" />
<Property Name="Token" Type="Edm.Guid" Nullable="false" />
<Property Name="Price" Type="Edm.Decimal" Nullable="false" />
<Property Name="Price" Type="Edm.Decimal" Nullable="false" Scale="Variable" />
<Property Name="Amount" Type="Edm.Int32" Nullable="false" />
<Annotation Term="OData.Community.Keys.V1.AlternateKeys">
<Collection>
Expand All @@ -96,6 +119,30 @@ You can get the following metadata.
</Record>
</Collection>
</Annotation>
<Annotation Term="Org.OData.Core.V1.AlternateKeys">
<Collection>
<Record>
<PropertyValue Property="Key">
<Collection>
<Record>
<PropertyValue Property="Alias" String="CoreName" />
<PropertyValue Property="Name" PropertyPath="Name" />
</Record>
</Collection>
</PropertyValue>
</Record>
<Record>
<PropertyValue Property="Key">
<Collection>
<Record>
<PropertyValue Property="Alias" String="CoreToken" />
<PropertyValue Property="Name" PropertyPath="Token" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</Annotation>
</EntityType>
<EntityType Name="Person">
<Key>
Expand Down Expand Up @@ -123,6 +170,24 @@ You can get the following metadata.
</Record>
</Collection>
</Annotation>
<Annotation Term="Org.OData.Core.V1.AlternateKeys">
<Collection>
<Record Type="Org.OData.Core.V1.AlternateKey">
<PropertyValue Property="Key">
<Collection>
<Record Type="Org.OData.Core.V1.PropertyRef">
<PropertyValue Property="Alias" String="core_c_r" />
<PropertyValue Property="Name" PropertyPath="CountryOrRegion" />
</Record>
<Record Type="Org.OData.Core.V1.PropertyRef">
<PropertyValue Property="Alias" String="core_passport" />
<PropertyValue Property="Name" PropertyPath="Passport" />
</Record>
</Collection>
</PropertyValue>
</Record>
</Collection>
</Annotation>
</EntityType>
</Schema>
<Schema Namespace="Default" xmlns="http://docs.oasis-open.org/odata/ns/edm">
Expand All @@ -142,7 +207,8 @@ Send one of the following requests

```C#
GET http://localhost:5219/odata/Customers(2)
GET http://localhost:5219/odata/Customers(ssn='SSN-2-102')
GET http://localhost:5219/odata/Customers(SSN='SSN-2-102')
GET http://localhost:5219/odata/Customers(CoreSN='SSN-2-102')
```

you can get the following result:
Expand All @@ -151,7 +217,12 @@ you can get the following result:
"@odata.context": "http://localhost:5219/odata/$metadata#Customers/$entity",
"Id": 2,
"Name": "Jerry",
"SSN": "SSN-2-102"
"SSN": "SSN-2-102",
"Titles": [
"abc",
null,
"efg"
]
}
```

Expand All @@ -163,6 +234,8 @@ Send one of the following requests
GET http://localhost:5219/odata/orders(3)
GET http://localhost:5219/odata/orders(Name='Order-3')
GET http://localhost:5219/odata/orders(Token=75036b94-c836-4946-8cc8-054cf54060ec)
GET http://localhost:5219/odata/Orders(CoreName='Order-3')
GET http://localhost:5219/odata/Orders(CoreToken=75036B94-C836-4946-8CC8-054CF54060EC)
```

you can get the following result:
Expand All @@ -183,7 +256,8 @@ Send one of the following requests

```C#
GET http://localhost:5219/odata/People(3)
GET ttp://localhost:5219/odata/People(c_or_r='USA',passport='9999')
GET http://localhost:5219/odata/People(c_or_r='USA',passport='9999')
GET http://localhost:5219/odata/People(core_c_r='USA',core_passport='9999')
```

you can get the following result:
Expand All @@ -196,3 +270,5 @@ you can get the following result:
"Passport": "9999"
}
```

Thanks!
Loading