Skip to content

Commit

Permalink
Update Cosmos docs
Browse files Browse the repository at this point in the history
Fixes #1729
Fixes #1771
  • Loading branch information
AndriySvyryd committed Nov 5, 2019
1 parent 3a78c01 commit 2d46f5b
Show file tree
Hide file tree
Showing 11 changed files with 99 additions and 72 deletions.
2 changes: 1 addition & 1 deletion entity-framework/core/modeling/data-seeding.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,4 @@ Depending on the constraints of your deployment the initialization code can be e
* Running the initialization app locally
* Deploying the initialization app with the main app, invoking the initialization routine and disabling or removing the initialization app.

This can usually be automated by using [publish profiles](https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/visual-studio-publish-profiles).
This can usually be automated by using [publish profiles](https://docs.microsoft.com/aspnet/core/host-and-deploy/visual-studio-publish-profiles).
53 changes: 35 additions & 18 deletions entity-framework/core/providers/cosmos/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ uid: core/providers/cosmos/index
This database provider allows Entity Framework Core to be used with Azure Cosmos DB. The provider is maintained as part of the [Entity Framework Core Project](https://github.com/aspnet/EntityFrameworkCore).

It is strongly recommended to familiarize yourself with the [Azure Cosmos DB documentation](https://docs.microsoft.com/en-us/azure/cosmos-db/introduction) before reading this section.
It is strongly recommended to familiarize yourself with the [Azure Cosmos DB documentation](https://docs.microsoft.com/azure/cosmos-db/introduction) before reading this section.

>[!NOTE]
> This provider only works with the SQL API of Azure Cosmos DB.
## Install

Expand Down Expand Up @@ -70,6 +73,23 @@ To map an entity type to a different container use `ToContainer`:

To identify the entity type that a given item represent EF Core adds a discriminator value even if there are no derived entity types. The name and value of the discriminator [can be changed](../../modeling/inheritance.md).

If no other entity type will ever be stored in the same container the discriminator can be removed by calling `HasNoDiscriminator()`:

[!code-csharp[NoDiscriminator](../../../../samples/core/Cosmos/ModelBuilding/OrderContext.cs?name=NoDiscriminator)]

### Partition keys

By default EF Core will create containers with the partition key set to `"__partitionKey"` without supplying any value for it when inserting items. But to fully leverage the performance capabilities of Azure Cosmos a [carefully selected partition key](https://docs.microsoft.com/azure/cosmos-db/partition-data) should be used. It can be configured by calling `.HasPartitionKey()`:

[!code-csharp[PartitionKey](../../../../samples/core/Cosmos/ModelBuilding/OrderContext.cs?name=PartitionKey)]

>[!NOTE]
>The partition key property can be of any type as long as it is [converted to string](xref:core/modeling/value-conversions).
Once configured the partition key property should always have a non-null value. When issuing a query a condition can be added to make it single-partition.

[!code-csharp[PartitionKey](../../../../samples/core/Cosmos/ModelBuilding/Sample.cs?name=PartitionKey)]

## Embedded Entities

For Cosmos owned entities are embedded in the same item as the owner. To change a property name use `ToJsonProperty`:
Expand All @@ -81,12 +101,11 @@ With this configuration the order from the example above is stored like this:
``` json
{
"Id": 1,
"Discriminator": "Order",
"PartitionKey": "1",
"TrackingNumber": null,
"id": "Order|1",
"id": "1",
"Address": {
"ShipsToCity": "London",
"Discriminator": "StreetAddress",
"ShipsToStreet": "221 B Baker St"
},
"_rid": "6QEKAM+BOOABAAAAAAAAAA==",
Expand Down Expand Up @@ -115,12 +134,10 @@ They will be persisted in this way:
"ShippingCenters": [
{
"City": "Phoenix",
"Discriminator": "StreetAddress",
"Street": "500 S 48th Street"
},
{
"City": "Anaheim",
"Discriminator": "StreetAddress",
"Street": "5650 Dolly Ave"
}
],
Expand Down Expand Up @@ -152,18 +169,18 @@ This is the resulting JSON:
``` json
{
"Id": 1,
"Discriminator": "Order",
"TrackingNumber": null,
"id": "Order|1",
"Address": {
"ShipsToCity": "London",
"Discriminator": "StreetAddress",
"ShipsToStreet": "3 Abbey Road"
},
"_rid": "6QEKAM+BOOABAAAAAAAAAA==",
"_self": "dbs/6QEKAA==/colls/6QEKAM+BOOA=/docs/6QEKAM+BOOABAAAAAAAAAA==/",
"_etag": "\"00000000-0000-0000-683c-8f7ac48f01d5\"",
"Discriminator": "Distributor",
"id": "Distributor|1",
"ShippingCenters": [
{
"City": "Phoenix",
"Street": "500 S 48th Street"
}
],
"_rid": "JBwtAN8oNYEBAAAAAAAAAA==",
"_self": "dbs/JBwtAA==/colls/JBwtAN8oNYE=/docs/JBwtAN8oNYEBAAAAAAAAAA==/",
"_etag": "\"00000000-0000-0000-9377-d7a1ae7c01d5\"",
"_attachments": "attachments/",
"_ts": 1568163739
"_ts": 1572917100
}
```
2 changes: 1 addition & 1 deletion entity-framework/core/providers/cosmos/limitations.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ The Cosmos provider has a number of limitations. Many of these limitations are a
## Azure Cosmos DB limitations

You can see the full overview of [Azure Cosmos DB supported features](https://docs.microsoft.com/en-us/azure/cosmos-db/modeling-data), these are the most notable differences compared to a relational database:
You can see the full overview of [Azure Cosmos DB supported features](https://docs.microsoft.com/azure/cosmos-db/modeling-data), these are the most notable differences compared to a relational database:

- Client-initiated transactions are not supported
- Some cross-partition queries are either not supported or much slower depending on the operators involved
7 changes: 3 additions & 4 deletions entity-framework/core/providers/cosmos/unstructured-data.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,11 @@ It is possible to access the properties that are not tracked by EF Core through
``` json
{
"Id": 1,
"Discriminator": "Order",
"PartitionKey": "1",
"TrackingNumber": null,
"id": "Order|1",
"id": "1",
"Address": {
"ShipsToCity": "London",
"Discriminator": "StreetAddress",
"ShipsToStreet": "221 B Baker St"
},
"_rid": "eLMaAK8TzkIBAAAAAAAAAA==",
Expand All @@ -44,7 +43,7 @@ It is possible to access the properties that are not tracked by EF Core through
## Using CosmosClient

To decouple completely from EF Core get the `CosmosClient` object that is [part of the Azure Cosmos DB SDK](https://docs.microsoft.com/en-us/azure/cosmos-db/sql-api-get-started) from `DbContext`:
To decouple completely from EF Core get the `CosmosClient` object that is [part of the Azure Cosmos DB SDK](https://docs.microsoft.com/azure/cosmos-db/sql-api-get-started) from `DbContext`:

[!code-csharp[CosmosClient](../../../../samples/core/Cosmos/UnstructuredData/Sample.cs?highlight=3&name=CosmosClient)]

Expand Down
2 changes: 1 addition & 1 deletion entity-framework/core/what-is-new/ef-core-2.2.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ EF Core 2.2 now supports working with spatial data from various databases using
Spatial data support is implemented as a series of provider-specific extension packages.
Each of these packages contributes mappings for NTS types and methods, and the corresponding spatial types and functions in the database.
Such provider extensions are now available for [SQL Server](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite/), [SQLite](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Sqlite.NetTopologySuite/), and [PostgreSQL](https://www.nuget.org/packages/Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite/) (from the [Npgsql project](https://www.npgsql.org/)).
Spatial types can be used directly with the [EF Core in-memory provider](https://docs.microsoft.com/en-us/ef/core/providers/in-memory/) without additional extensions.
Spatial types can be used directly with the [EF Core in-memory provider](xref:core/providers/in-memory/index) without additional extensions.

Once the provider extension is installed, you can add properties of supported types to your entities. For example:

Expand Down
2 changes: 1 addition & 1 deletion samples/core/Cosmos/Cosmos.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Cosmos" Version="3.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Cosmos" Version="3.1.0-preview2.19525.5" />
</ItemGroup>

</Project>
1 change: 1 addition & 0 deletions samples/core/Cosmos/ModelBuilding/Distributor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace Cosmos.ModelBuilding
public class Distributor
{
public int Id { get; set; }
public string StoreId { get; set; }
public ICollection<StreetAddress> ShippingCenters { get; set; }
}
#endregion
Expand Down
2 changes: 1 addition & 1 deletion samples/core/Cosmos/ModelBuilding/Order.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public class Order
{
public int Id { get; set; }
public int? TrackingNumber { get; set; }
//public string PartitionKey { get; set; }
public string PartitionKey { get; set; }
public StreetAddress ShippingAddress { get; set; }
}
#endregion
Expand Down
9 changes: 7 additions & 2 deletions samples/core/Cosmos/ModelBuilding/OrderContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,14 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
.ToContainer("Orders");
#endregion

#region NoDiscriminator
modelBuilder.Entity<Order>()
.HasNoDiscriminator();
#endregion

#region PartitionKey
//modelBuilder.Entity<Order>()
// .HasPartitionKey(o => o.PartitionKey);
modelBuilder.Entity<Order>()
.HasPartitionKey(o => o.PartitionKey);
#endregion

#region PropertyNames
Expand Down
84 changes: 44 additions & 40 deletions samples/core/Cosmos/ModelBuilding/Sample.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,17 @@ public static async Task Run()
Console.WriteLine();

#region HelloCosmos
var londonOrder = new Order
{
Id = 1,
ShippingAddress = new StreetAddress { City = "London", Street = "221 B Baker St" }
};

using (var context = new OrderContext())
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();

context.Add(londonOrder);
context.Add(new Order
{
Id = 1,
ShippingAddress = new StreetAddress { City = "London", Street = "221 B Baker St" },
PartitionKey = "1"
});

await context.SaveChangesAsync();
}
Expand All @@ -35,40 +34,44 @@ public static async Task Run()
{
var order = await context.Orders.FirstAsync();
Console.WriteLine($"First order will ship to: {order.ShippingAddress.Street}, {order.ShippingAddress.City}");
Console.WriteLine();
}
#endregion

#region PartitionKey
//using (var context = new OrderContext())
//{
// context.Add(new Order
// {
// Id = 2,
// ShippingAddress = new StreetAddress { City = "New York", Street = "11 Wall Street" },
// PartitionKey = "1"
// });

// context.SaveChangesAsync();
//}

//using (var context = new OrderContext())
//{
// var order = context.Orders.LastAsync();
// Console.WriteLine($"Last order will ship to: {order.ShippingAddress.Street}, {order.ShippingAddress.City}");
//}
using (var context = new OrderContext())
{
context.Add(new Order
{
Id = 2,
ShippingAddress = new StreetAddress { City = "New York", Street = "11 Wall Street" },
PartitionKey = "2"
});

await context.SaveChangesAsync();
}

using (var context = new OrderContext())
{
var order = await context.Orders.Where(p => p.PartitionKey == "2").LastAsync();
Console.WriteLine($"Last order will ship to: {order.ShippingAddress.Street}, {order.ShippingAddress.City}");
Console.WriteLine();
}
#endregion

#region OwnedCollection
using (var context = new OrderContext())
var distributor = new Distributor
{
context.Add(new Distributor
{
Id = 1,
ShippingCenters = new HashSet<StreetAddress> {
Id = 1,
ShippingCenters = new HashSet<StreetAddress> {
new StreetAddress { City = "Phoenix", Street = "500 S 48th Street" },
new StreetAddress { City = "Anaheim", Street = "5650 Dolly Ave" }
}
});
};

using (var context = new OrderContext())
{
context.Add(distributor);

await context.SaveChangesAsync();
}
Expand All @@ -84,28 +87,29 @@ public static async Task Run()
var addressPKProperties = addressEntry.Metadata.FindPrimaryKey().Properties;

Console.WriteLine($"First shipping center PK: ({addressEntry.Property(addressPKProperties[0].Name).CurrentValue}, {addressEntry.Property(addressPKProperties[1].Name).CurrentValue})");
Console.WriteLine();
}
#endregion

#region Attach
using (var context = new OrderContext())
{
var orderEntry = context.Add(londonOrder);
orderEntry.State = EntityState.Unchanged;
var distributorEntry = context.Add(distributor);
distributorEntry.State = EntityState.Unchanged;

londonOrder.ShippingAddress.Street = "3 Abbey Road";
distributor.ShippingCenters.Remove(distributor.ShippingCenters.Last());

await context.SaveChangesAsync();
}

using (var context = new OrderContext())
{
var order = await context.Orders.FirstAsync();
Console.WriteLine($"First order will now ship to: {order.ShippingAddress.Street}, {order.ShippingAddress.City}");
var firstDistributor = await context.Distributors.FirstAsync();
Console.WriteLine($"Number of shipping centers is now: {firstDistributor.ShippingCenters.Count}");

var orderEntry = context.Entry(order);
var idProperty = orderEntry.Property<string>("id");
Console.WriteLine($"The order 'id' is: {idProperty.CurrentValue}");
var distributorEntry = context.Entry(firstDistributor);
var idProperty = distributorEntry.Property<string>("StoreId");
Console.WriteLine($"The distributor 'id' is: {idProperty.CurrentValue}");
}
#endregion
}
Expand Down
7 changes: 4 additions & 3 deletions samples/core/Cosmos/UnstructuredData/Sample.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ public static async Task Run()
#region Unmapped
using (var context = new OrderContext())
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();

var order = new Order
{
Id = 1,
ShippingAddress = new StreetAddress { City = "London", Street = "221 B Baker St" }
ShippingAddress = new StreetAddress { City = "London", Street = "221 B Baker St" },
PartitionKey = "1"
};

context.Add(order);
Expand Down

0 comments on commit 2d46f5b

Please sign in to comment.