简体   繁体   English

实体框架在子类上是唯一的

[英]Entity Framework unique on child class

I am confused about how this kind of situation should be handled in Entity Framework. 我对如何在实体框架中处理这种情况感到困惑。

I have a character base class: 我有一个角色基础类:

public class Character
{
    [Key]
    public Guid Id { get; set; }
    public Realm Realm { get; set; }
    public Guid RealmId { get; set; }
    public string Name { get; set; }
}

Character has name and is bound to realm. 角色具有名称,并且绑定到领域。

Character controlled by a player is definitely a character. 玩家控制的角色绝对是角色。 It is bound to a player/user: 它绑定到播放器/用户:

public class PlayerCharacter : Character
{        
    public User User { get; set; }
    public Guid UserId { get; set; }
}

NPC is also a character: it does not need to have any properties for a MCVE NPC也是一个角色:它不需要具有MCVE的任何属性

public class Npc : Character { }

Now, obviously, you would not want to have to characters on the same realm with the same name, but you can have as many Orcs as you need on a single realm, so we would need to define unique constraint on PlayerCharacter , for example via .HasAlternateKey : 现在,显然,您不想在同一个领域中使用相同名称的字符,但是在一个领域中可以拥有任意数量的Orcs ,因此我们需要在PlayerCharacter上定义唯一的约束,例如通过.HasAlternateKey

public DbSet<PlayerCharacter> Characters { get; set; }
public DbSet<Npc> Npcs { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<PlayerCharacter>()
        .HasAlternateKey("Name", "RealmId");
}

Now we add migration: 现在我们添加迁移:

$ dotnet ef migrations add 5
System.InvalidOperationException: A key cannot be configured on 
'PlayerCharacter' because it is a derived type. The key must be 
configured on the root type 'Character'.

Ok, how about a unique index? 好的,唯一索引如何?

modelBuilder.Entity<PlayerCharacter>()
    .HasIndex("Name", "RealmId")
    .IsUnique();

$ dotnet ef migrations add 5
Done. To undo this action, use 'ef migrations remove'

It worked! 有效! But wait: 可是等等:

migrationBuilder.CreateTable(
    name: "Character",
    columns: table => new
    {
        Id = table.Column<Guid>(nullable: false),
        Discriminator = table.Column<string>(nullable: false),
        Name = table.Column<string>(nullable: true),
        RealmId = table.Column<Guid>(nullable: false),
        // other props...
    },
    constraints: table =>
    {
        table.PrimaryKey("PK_Character", x => x.Id);
        // foreign keys...
    });

migrationBuilder.CreateIndex(
    name: "IX_Character_Name_RealmId",
    table: "Character",
    columns: new[] { "Name", "RealmId" },
    unique: true);

Now both player characters and npcs are unique by name! 现在,玩家角色和NPC在名称上都是唯一的! How can I set unique only in derived class? 如何仅在派生类中设置唯一性?

The only way you can do it currently (EF Core 2.0.1) is to use filtered unique index based on Discriminator column value. 当前唯一可以执行此操作的方法(EF Core 2.0.1)是使用基于Discriminator值的过滤后的唯一索引。

Unfortunately the HasFilter fluent API is not db agnostic. 不幸的是, HasFilter流利的API不是数据库不可知的。 Here is the configuration for SqlServer: 这是SqlServer的配置:

modelBuilder.Entity<PlayerCharacter>()
    .HasIndex("Name", "RealmId")
    .IsUnique()
    .HasFilter("Discriminator = 'PlayerCharacter'"); // <--

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM