Je me demande s'il y a une annotation de données pour une contrainte unique dans la première approche du code Entity Framework Core 2?
Dans EF Core, vous pouvez utiliser la méthode d'extension HasAlternateKey
dans l'API couramment uniquement. Il n'y a aucune annotation de données pour réaliser une contrainte unique .
Cet article MS doc - Clés alternatives (contraintes uniques) - expliquera comment utiliser et quelles autres possibilités existent.
Un court exemple du lien ci-dessus:
class MyContext : DbContext
{
public DbSet<Car> Cars { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>()
.HasAlternateKey(c => c.LicensePlate)
.HasName("AlternateKey_LicensePlate");
}
}
class Car
{
public int CarId { get; set; }
public string LicensePlate { get; set; }
public string Make { get; set; }
public string Model { get; set; }
}
Il est également possible de définir un index unique . Pour cela, dans EF Core, vous devez utiliser dans l'API couramment la méthode d'extension HasIndex
( aucune annotation de données ). Dans cet article MS doc - Index - vous trouverez plus d'informations.
Et voici un exemple pour un index unique:
class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasIndex(b => b.Url)
.IsUnique();
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
J'ai écrit une classe d'attributs qui peut vous permettre de décorer les propriétés de votre classe EF Core Entity pour générer une clé unique (sans l'API Fluent).
using System;
using System.ComponentModel.DataAnnotations;
/// <summary>
/// Used on an EntityFramework Entity class to mark a property to be used as a Unique Key
/// </summary>
[AttributeUsageAttribute(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public class UniqueKeyAttribute : ValidationAttribute
{
/// <summary>
/// Marker attribute for unique key
/// </summary>
/// <param name="groupId">Optional, used to group multiple entity properties together into a combined Unique Key</param>
/// <param name="order">Optional, used to order the entity properties that are part of a combined Unique Key</param>
public UniqueKeyAttribute(string groupId = null, int order = 0)
{
GroupId = groupId;
Order = order;
}
public string GroupId { get; set; }
public int Order { get; set; }
}
Dans votre fichier DbContext.cs, à l'intérieur de la méthode OnModelCreating (modelBuilder), ajoutez ceci:
// Iterate through all EF Entity types
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
#region Convert UniqueKeyAttribute on Entities to UniqueKey in DB
var properties = entityType.GetProperties();
if ((properties != null) && (properties.Any()))
{
foreach (var property in properties)
{
var uniqueKeys = GetUniqueKeyAttributes(entityType, property);
if (uniqueKeys != null)
{
foreach (var uniqueKey in uniqueKeys.Where(x => x.Order == 0))
{
// Single column Unique Key
if (String.IsNullOrWhiteSpace(uniqueKey.GroupId))
{
entityType.AddIndex(property).IsUnique = true;
}
// Multiple column Unique Key
else
{
var mutableProperties = new List<IMutableProperty>();
properties.ToList().ForEach(x =>
{
var uks = GetUniqueKeyAttributes(entityType, x);
if (uks != null)
{
foreach (var uk in uks)
{
if ((uk != null) && (uk.GroupId == uniqueKey.GroupId))
{
mutableProperties.Add(x);
}
}
}
});
entityType.AddIndex(mutableProperties).IsUnique = true;
}
}
}
}
}
#endregion Convert UniqueKeyAttribute on Entities to UniqueKey in DB
}
Toujours dans votre classe DbContext.cs, ajoutez cette méthode privée:
private static IEnumerable<UniqueKeyAttribute> GetUniqueKeyAttributes(IMutableEntityType entityType, IMutableProperty property)
{
if (entityType == null)
{
throw new ArgumentNullException(nameof(entityType));
}
else if (entityType.ClrType == null)
{
throw new ArgumentNullException(nameof(entityType.ClrType));
}
else if (property == null)
{
throw new ArgumentNullException(nameof(property));
}
else if (property.Name == null)
{
throw new ArgumentNullException(nameof(property.Name));
}
var propInfo = entityType.ClrType.GetProperty(
property.Name,
BindingFlags.NonPublic |
BindingFlags.Public |
BindingFlags.Static |
BindingFlags.Instance |
BindingFlags.DeclaredOnly);
if (propInfo == null)
{
return null;
}
return propInfo.GetCustomAttributes<UniqueKeyAttribute>();
}
Utilisation dans votre classe Entity.cs:
public class Company
{
[Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid CompanyId { get; set; }
[Required]
[UniqueKey(groupId: "1", order: 0)]
[StringLength(100, MinimumLength = 1)]
public string CompanyName { get; set; }
}
Vous pouvez même l'utiliser sur plusieurs propriétés pour former une clé unique sur plusieurs colonnes de votre table. (Notez l'utilisation de "groupId" puis de la "commande")
public class Company
{
[Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid CompanyId { get; set; }
[Required]
[UniqueKey(groupId: "1", order: 0)]
[StringLength(100, MinimumLength = 1)]
public string CompanyName { get; set; }
[Required]
[UniqueKey(groupId: "1", order: 1)]
[StringLength(100, MinimumLength = 1)]
public string CompanyLocation { get; set; }
}