EF Core Azure Cosmos DB Sağlayıcısı
Bu veritabanı sağlayıcısı, Entity Framework Core Azure veritabanı ile birlikte Cosmos sağlar. Sağlayıcı, sağlayıcının bir parçası olarak Entity Framework Core Project.
Bu bölümü okumadan önce Azure Cosmos DB belgelerini tanımanız önemle önerilir.
Not
Bu sağlayıcı yalnızca Azure Cosmos DB'nin SQL API'si ile çalışır.
Yükleme
Microsoft.EntityFrameworkCore.Cosmos NuGet paketi.
dotnet add package Microsoft.EntityFrameworkCore.Cosmos
başlarken
İpucu
Bu makalenin örneğini GitHub.
Diğer sağlayıcılarda olduğu gibi ilk adım UseCosmos çağrısı yapmaktır:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseCosmos(
"https://localhost:8081",
"C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==",
databaseName: "OrdersDB");
Uyarı
Uç nokta ve anahtar kolaylık sağlamak için buraya sabit kodlanmış, ancak bir üretim uygulamasında bunların güvenli bir şekilde depolanmış olması gerekir.
Bu Order örnekte, sahip olunan türüne başvuru içeren basit OrderStreetAddress
public class Order
{
public int Id { get; set; }
public int? TrackingNumber { get; set; }
public string PartitionKey { get; set; }
public StreetAddress ShippingAddress { get; set; }
}
public class StreetAddress
{
public string Street { get; set; }
public string City { get; set; }
}
Verileri kaydetme ve sorgulama normal EF desenini izler:
using (var context = new OrderContext())
{
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
context.Add(
new Order
{
Id = 1, ShippingAddress = new StreetAddress { City = "London", Street = "221 B Baker St" }, PartitionKey = "1"
});
await context.SaveChangesAsync();
}
using (var context = new OrderContext())
{
var order = await context.Orders.FirstAsync();
Console.WriteLine($"First order will ship to: {order.ShippingAddress.Street}, {order.ShippingAddress.City}");
Console.WriteLine();
}
Önemli
Gerekli kapsayıcıları oluşturmak ve modelde varsa çekirdek verilerini eklemek için EnsureCreatedAsync çağrısı yapmak gerekir. Ancak, EnsureCreatedAsync performans sorunlarına neden olduğu için normal işlem değil yalnızca dağıtım sırasında çağrılmalısınız.
Cosmos seçenekleri
Cosmos DB sağlayıcısını tek bir bağlantı dizesiyle yapılandırmak ve bağlantıyı özelleştirmek için diğer seçenekleri belirtmek de mümkündür:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseCosmos(
"AccountEndpoint=https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==",
databaseName: "OptionsDB",
options =>
{
options.ConnectionMode(ConnectionMode.Gateway);
options.WebProxy(new WebProxy());
options.LimitToEndpoint();
options.Region(Regions.AustraliaCentral);
options.GatewayModeMaxConnectionLimit(32);
options.MaxRequestsPerTcpConnection(8);
options.MaxTcpConnectionsPerEndpoint(16);
options.IdleTcpConnectionTimeout(TimeSpan.FromMinutes(1));
options.OpenTcpConnectionTimeout(TimeSpan.FromMinutes(1));
options.RequestTimeout(TimeSpan.FromMinutes(1));
});
Not
Bu seçeneklerin çoğu 5.0 EF Core tanıtıldı.
İpucu
Yukarıda belirtilen her Cosmos etkisinin ayrıntılı açıklaması için Azure veritabanı veritabanı seçenekleri belgelerine bakın.
Cosmos model özelleştirmesi
Varsayılan olarak, tüm varlık türleri türetilmiş bağlama (bu durumda) göre adlandırılmış aynı "OrderContext" kapsayıcıyla eşlenmiş olur. Varsayılan kapsayıcı adını değiştirmek için HasDefaultContainer kullanın:
modelBuilder.HasDefaultContainer("Store");
Bir varlık türünü farklı bir kapsayıcıyla eşlemek için ToContainer kullanın:
modelBuilder.Entity<Order>()
.ToContainer("Orders");
Bir öğenin bir öğeyi temsil eden varlık türünü EF Core türetilen varlık türleri olsa bile bir ayrımcı değer ekler. Ayırıcının adı ve değeri değiştirilebilir.
Aynı kapsayıcıda başka bir varlık türü depolanmayacaksa HasNoDiscriminator çağrılarak ayrımcı kaldırılabilir:
modelBuilder.Entity<Order>()
.HasNoDiscriminator();
Bölüm anahtarları
Varsayılan EF Core, öğeleri eklerken için herhangi bir değer vermeden bölüm anahtarı olarak ayarlanmış "__partitionKey" kapsayıcılar oluşturur. Ancak Azure'ın performans özelliklerini tam olarak Cosmos dikkatle seçilen bir bölüm anahtarı kullanılmalıdır. HasPartitionKey çağrılarak yalıt nır:
modelBuilder.Entity<Order>()
.HasPartitionKey(o => o.PartitionKey);
Not
Bölüm anahtarı özelliği, dizesine dönüştürülmesi sürece herhangi bir türde olabilir.
Bölüm anahtarı özelliği yapılandırıldığında her zaman null olmayan bir değer olmalıdır. Bir WithPartitionKey çağrısı ekleyerek tek bölümli sorgular olabilir.
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.WithPartitionKey("2").LastAsync();
Console.WriteLine($"Last order will ship to: {order.ShippingAddress.Street}, {order.ShippingAddress.City}");
Console.WriteLine();
}
Not
WithPartitionKey, 5.0 EF Core tanıtıldı.
Genellikle, sunucu semantiği en iyi şekilde yansıtacak ve örneğin içinde bazı iyileştirmelere izin veren bölüm anahtarını birincil anahtara eklemeniz FindAsync önerilir.
Katıştırılmış varlıklar
Örneğin Cosmos varlıklar sahiple aynı öğeye eklenmiş olur. Özellik adını değiştirmek için ToJsonProperty kullanın:
modelBuilder.Entity<Order>().OwnsOne(
o => o.ShippingAddress,
sa =>
{
sa.ToJsonProperty("Address");
sa.Property(p => p.Street).ToJsonProperty("ShipsToStreet");
sa.Property(p => p.City).ToJsonProperty("ShipsToCity");
});
Bu yapılandırma ile yukarıdaki örnekteki sipariş aşağıdaki gibi depolanır:
{
"Id": 1,
"PartitionKey": "1",
"TrackingNumber": null,
"id": "1",
"Address": {
"ShipsToCity": "London",
"ShipsToStreet": "221 B Baker St"
},
"_rid": "6QEKAM+BOOABAAAAAAAAAA==",
"_self": "dbs/6QEKAA==/colls/6QEKAM+BOOA=/docs/6QEKAM+BOOABAAAAAAAAAA==/",
"_etag": "\"00000000-0000-0000-683c-692e763901d5\"",
"_attachments": "attachments/",
"_ts": 1568163674
}
Sahip olunan varlık koleksiyonları da gömülür. Bir sonraki örnekte sınıfını Distributor koleksiyonuyla birlikte kullanılasmız: StreetAddress
public class Distributor
{
public int Id { get; set; }
public string ETag { get; set; }
public ICollection<StreetAddress> ShippingCenters { get; set; }
}
Sahip olunan varlıkların depolanmış açık anahtar değerleri sağlamaları gerekmez:
var distributor = new Distributor
{
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();
}
Bunlar şu şekilde kalıcı olur:
{
"Id": 1,
"Discriminator": "Distributor",
"id": "Distributor|1",
"ShippingCenters": [
{
"City": "Phoenix",
"Street": "500 S 48th Street"
},
{
"City": "Anaheim",
"Street": "5650 Dolly Ave"
}
],
"_rid": "6QEKANzISj0BAAAAAAAAAA==",
"_self": "dbs/6QEKAA==/colls/6QEKANzISj0=/docs/6QEKANzISj0BAAAAAAAAAA==/",
"_etag": "\"00000000-0000-0000-683c-7b2b439701d5\"",
"_attachments": "attachments/",
"_ts": 1568163705
}
Şirket EF Core her zaman tüm izilen varlıklar için benzersiz anahtar değerlerine sahip olması gerekir. Sahip olunan tür koleksiyonları için varsayılan olarak oluşturulan birincil anahtar, sahibi işaret alan yabancı anahtar özelliklerden ve JSON dizisinde dizine karşılık gelen int bir özellikten oluşur. Bu değerleri almak için giriş API'si kullanılabilir:
using (var context = new OrderContext())
{
var firstDistributor = await context.Distributors.FirstAsync();
Console.WriteLine($"Number of shipping centers: {firstDistributor.ShippingCenters.Count}");
var addressEntry = context.Entry(firstDistributor.ShippingCenters.First());
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();
}
İpucu
Gerektiğinde sahip olunan varlık türleri için varsayılan birincil anahtar değiştirilebilir, ancak anahtar değerleri açıkça sağlanmalıdır.
Bağlantısı kesilmiş varlıklarla çalışma
Her öğenin, verilen id bölüm anahtarı için benzersiz bir değere sahip olması gerekir. Varsayılan EF Core, sınırlayıcı olarak '|' kullanarak ayrımcıyı ve birincil anahtar değerlerini bir arada kullanarak değeri üretir. Anahtar değerleri yalnızca bir varlık durumuna girdiği zaman Added oluşturulur. Bu durum, değeri depolamak için .NET türünde bir özelliği yoksa varlıkları eklemede soruna neden olabilir.
Bu sınırlamaya bir çözüm olarak el ile değer oluşturabilir ve ayarlama veya önce varlığı eklendi olarak işaretleme ve ardından id istenen durumla değiştirme:
using (var context = new OrderContext())
{
var distributorEntry = context.Add(distributor);
distributorEntry.State = EntityState.Unchanged;
distributor.ShippingCenters.Remove(distributor.ShippingCenters.Last());
await context.SaveChangesAsync();
}
using (var context = new OrderContext())
{
var firstDistributor = await context.Distributors.FirstAsync();
Console.WriteLine($"Number of shipping centers is now: {firstDistributor.ShippingCenters.Count}");
var distributorEntry = context.Entry(firstDistributor);
var idProperty = distributorEntry.Property<string>("__id");
Console.WriteLine($"The distributor 'id' is: {idProperty.CurrentValue}");
}
Sonuçta elde edilen JSON şu şekildedir:
{
"Id": 1,
"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": 1572917100
}
eTag'lerle İyimser eşzamanlılık
Not
eTag eşzamanlılığı desteği, 5.0'EF Core tanıtılmıştır.
Bir varlık türünü iyimser eşzamanlılık kullanmak üzere yapılandırmak için UseETagConcurrency çağrısı. Bu çağrı gölge _etag durumda bir özellik _etag ve eşzamanlılık belirteci olarak ayarlayın.
modelBuilder.Entity<Order>()
.UseETagConcurrency();
Eşzamanlılık hatalarını çözmeyi kolaylaştırmak için IsETagConcurrencykullanarak eTag'i bir CLR özelliğine eşlersiniz.
modelBuilder.Entity<Distributor>()
.Property(d => d.ETag)
.IsETagConcurrency();