TL/DR - 有没有一种方法可以强制EF Core允许我更新Discriminator列?
我第一次尝试使用Entity Framework Core,并尝试实现一个简单的系统,其中我需要管理三种类型的客户。其中两种类型在其类型值本身上只有意义上的不同(type1
和type2
)。第三种类型(special
)具有更多可能关系的扩展集。
因此,在数据库中,我创建了一个单独的表来存储核心数据:
CREATE TABLE [Clients].[Clients](
[ClientId] [varchar](30) NOT NULL,
[ClientName] [varchar](100) NOT NULL,
[ProtocolType] [varchar](30) NOT NULL,
[ClientLogoUrl] [varchar](max) NULL,
CONSTRAINT [PK_Clients_Clients] PRIMARY KEY ([ClientId]),
CONSTRAINT [UQ_Clients_Client_Names] UNIQUE ([ClientName]),
CONSTRAINT [UQ_Clients_Client_Protocol_XRef] UNIQUE ([ClientId],[ProtocolType]),
CONSTRAINT [FK_Clients_Client_Protocol] FOREIGN KEY([ProtocolType])
REFERENCES [Clients].[Protocols] ([ProtocolType])
)
在我的代码中,我创建了以下这些模型:
public class Client
{
public string ClientId { get; set; }
public string ClientName { get; set; }
public string ProtocolType { get; set; }
public string ClientLogoUrl { get; set; }
public Protocol Protocol { get; set; }
}
对于那些具有更多可能关系的客户子类型:
public class SpecialClient : Client
{
public List<Service> Services { get; set; }
//And more
}
最初我将此映射为OnModelCreating
中的:
modelBuilder.Entity<Clients.Client>()
.HasDiscriminator<string>("ProtocolType")
.HasValue<Clients.SpecialClient>("special");
但是,这样只会查询数据库中协议类型为special
和Client
的记录 - 这不是我想要的。我本以为EF会为“所有其他值”使用基类,但它并没有这样做。因此,我尝试了以下方法:
modelBuilder.Entity<Clients.Client>()
.HasDiscriminator<string>("ProtocolType")
.HasValue<Clients.SpecialClient>("special")
.HasValue<Clients.Client>("type1")
.HasValue<Clients.Client>("type2");
但是这样做实际上只获取了最后提供的值,并且只查询了数据库中的special
和type2
。所以,我最终接受了需要引入一个多余的额外类的事实,该类没有任何额外功能,只是为了让映射器满意:
public class Type2Client : Client {}
并且:
modelBuilder.Entity<Clients.Client>()
.HasDiscriminator<string>("ProtocolType")
.HasValue<Clients.SpecialClient>("special")
.HasValue<Clients.Client>("type1")
.HasValue<Clients.Type2Client>("type2");
最后——EF感到高兴,一切都很好,我可以继续我的生活了。然而,下一个挑战是客户端可以更改协议。
所以,我加载一个客户端。我更改它的协议类型。我保存它:
_context.Update(client);
await _context.SaveChangesAsync();
而 EF 生成的 SQL 如下:
SET NOCOUNT ON;
UPDATE [Clients].[Clients] SET [ClientLogoUrl] = @p0, [ClientName] = @p1
WHERE [ClientId] = @p2;
SELECT @@ROWCOUNT;
嗯,ProtocolType
列没有SET
关键字。有什么巧妙的方法可以让它工作吗?