TL / DR - 有没有办法强制EF Core允许我更新Discriminator列?
我第一次使用Entity Framework Core并试图实现一个简单的系统,我可以管理3种类型的客户端。其中两种类型的类型值本身只有显着差异(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只使用基类来表示&#34;所有其他值&#34;但事实并非如此。所以我试过了:
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;
Harumph。 SET
列没有ProtocolType
。是否有一些狡猾的方法来使这项工作?
答案 0 :(得分:2)
您需要更改鉴别器列的默认“保存后”行为。默认情况下,鉴别器列的AfterSaveBehavior
设置为Throw
。这意味着如果设置或更改了显式值,则在尝试保存更改时会抛出异常。这也意味着Update
不会将此类属性标记为已修改,因为这会导致SaveChanges
期间出现异常。
因此,在您的情况下,将保存行为更改为Save
的鉴别器列(当然,在您创建此列鉴别器后执行此操作):
modelBuilder.Entity<Client>()
.Property(c => c.ProtocolType).Metadata.AfterSaveBehavior = PropertySaveBehavior.Save;
它应该像你期望的那样工作。