Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/292.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# EF Core中是否有唯一约束的数据注释(代码优先)?_C#_Ef Code First_Entity Framework Core_Ef Core 2.0 - Fatal编程技术网

C# EF Core中是否有唯一约束的数据注释(代码优先)?

C# EF Core中是否有唯一约束的数据注释(代码优先)?,c#,ef-code-first,entity-framework-core,ef-core-2.0,C#,Ef Code First,Entity Framework Core,Ef Core 2.0,我想知道在Entity Framework Core 2代码优先方法中是否有唯一约束的数据注释?在EF Core中,您只能在fluent API中使用扩展方法HasAlternateKey。没有数据注释来实现唯一约束 这篇MS doc文章将解释如何使用以及存在哪些进一步的可能性 上面链接中的一个简短示例: class MyContext : DbContext { public DbSet<Car> Cars { get; set; } protected over

我想知道在Entity Framework Core 2代码优先方法中是否有唯一约束的数据注释?

在EF Core中,您只能在fluent API中使用扩展方法
HasAlternateKey
没有数据注释来实现唯一约束

这篇MS doc文章将解释如何使用以及存在哪些进一步的可能性

上面链接中的一个简短示例:

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; }
}

我已经编写了一个属性类,它可以让您修饰EF核心实体类属性,从而生成一个唯一的键(没有Fluent API)

您甚至可以跨多个属性使用它,以便跨表中的多个列形成唯一键。(注意使用“groupId”和“order”)


DbContext.cs
文件中的
onmodellcreating(modelBuilder)
方法中,在上一个
ForEach
中,我有
.OrderBy(o=>o.Order)
要更新,现在有一个代码优先的注释

[索引(nameof(MyProperty),IsUnique=true)]//使用Microsoft.EntityFrameworkCore
公共类MyClass
{
[Key,DatabaseGenerated(DatabaseGeneratedOption.None)]
公共Guid Id{get;set;}
[字符串长度(255),必填]
公共字符串MyProperty{get;set;}
}

让我们知道您需要它。@bricelam,谢谢,我已经这样做了。奇怪的是,当它已经是EF6的一部分时,他们删除了这个功能。令人恼火的是,您几乎可以通过数据注释属性完成所有事情,但仍有一些事情需要求助于fluent API。有更多事情只能通过fluent API完成,因为fluent API比注释更灵活、更具表现力。当一个映射构造涉及多个实体和/或属性时,注释只不过是意大利面条式编程。如果可以升级.NET Core版本,则解决方案如下:。HasIndex和IsUnique不使用nvarchar(字符串)类型的列.据我所知,如果它的长度小于900字节,您可以使用NVARCHAR或VARCHAR。您可以为具有fluent API或属性的列定义它。上面的示例代码直接来自链接的MS文档文章。如果将GUID的最大长度(例如32)设置为[N]VARCHAR(max),则应该可以工作。也许这个答案对你也有帮助。stackoverflow.com/a/27687748这个答案有很多问题。如果
Order
不是
0
则跳过UniqueKey属性。此外,它在创建复合唯一键时会抛出异常,因为它试图创建重复索引(复合索引的每个成员一个索引)。虽然它向我展示了如何让代码正常工作,但我想……如果您使用的是单个属性UniqueKey(或多个属性UniqueKey),则必须使用基于零的顺序值——对于每个用UniqueKeyAttribute修饰的属性。如果您没有正确地使用顺序,那么我可以想象您在哪里得到抛出的异常。正确使用从零开始的顺序,并对否定性表现出更多的限制。你是指OnModelCreating而不是onmodelGeneration吗?@D.Kermott文档说明,像IsUnique()这样的调用需要在OnModelCreating()中调用,因此Justin肯定是指OnModelCreating.FYI IsValid()override addedI不想否决,你最好删除这个答案。与问题无关谢谢你的关注,但我认为按正确的顺序使用多个键很重要,不是吗?否则,拥有此属性(0除外)有什么意义?它与问题有什么关系?我无法为属性的使用添加注释,所以我在这里添加了它,它与问题有关,不是吗?
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; }
}
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;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        // we simply return success as no actual data validation is needed because this class implements a "marker attribute" for "create a unique index"
        return ValidationResult.Success;
    }

    public string GroupId { get; set; }
    public int Order { get; set; }
}
// 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
}
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>();
}
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; }
}
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; }
}