[英]In EF Core, how do I configure the foreign key for reference owned types using Fluent API
[英]EF Core Foreign Key: incompatible types
我查看了許多類似的問題,但沒有找到適用的解決方案。
我在測試期間收到以下錯誤消息:
System.InvalidOperationException:從 'Product.FeatureType' 到 'FeatureType.Product' 與外鍵屬性 {'Type': string} 的關系不能以主鍵 {'Id': Guid} 為目標,因為它不兼容。 為此關系配置一個主鍵或一組兼容的外鍵屬性。
外鍵應該是FeatureType
的Type
字段。
這只發生在我將Product.Type
的類型設置為string
而不是Guid
時。 但它應該是一個string
,而不是一個Guid
。 我根本不明白這里有什么問題。 我以 DB-first 方法進行項目,使用此邏輯可以使用 SQL 毫無問題地創建數據庫。 我感謝每一個幫助。
編輯:這是我的 MSSQL model:
CREATE TABLE [Core].[FeatureType](
[id] [uniqueidentifier] NOT NULL,
[int_id] [int] IDENTITY(1,1) NOT NULL,
[type] [varchar](50) NOT NULL UNIQUE,
[description] [uniqueidentifier] NULL,
[SysStartTime] [datetime2](7) GENERATED ALWAYS AS ROW START NOT NULL,
[SysEndTime] [datetime2](7) GENERATED ALWAYS AS ROW END NOT NULL,
CONSTRAINT [PK_FeatureType] PRIMARY KEY NONCLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
PERIOD FOR SYSTEM_TIME ([SysStartTime], [SysEndTime])
) ON [PRIMARY]
WITH
(
SYSTEM_VERSIONING = ON ( HISTORY_TABLE = [Core].[FeatureTypeHistory] )
)
GO
CREATE TABLE [Core].[Product](
[id] [uniqueidentifier] NOT NULL,
[name] [varchar](100) NOT NULL UNIQUE,
[type] [varchar](50) NOT NULL FOREIGN KEY REFERENCES [Core].[FeatureType](type),
[SysStartTime] [datetime2](7) GENERATED ALWAYS AS ROW START NOT NULL,
[SysEndTime] [datetime2](7) GENERATED ALWAYS AS ROW END NOT NULL,
CONSTRAINT [PK_Product] PRIMARY KEY NONCLUSTERED ([id] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY],
PERIOD FOR SYSTEM_TIME ([SysStartTime], [SysEndTime])
) ON [PRIMARY] WITH (SYSTEM_VERSIONING = ON ( HISTORY_TABLE = [Core].[ProductHistory] ))
GO
據我了解,這應該可行,因為FeatureType
表的Type
列是UNIQUE
。
我有以下型號:
public class Product : IDBModel
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public DateTime SysStartTime { get; set; }
public DateTime SysEndTime { get; set; }
public FeatureType FeatureType { get; }
}
public class FeatureType : IDBModel
{
public Guid Id { get; set; }
public string Type { get; set; }
public Guid? Description { get; set; }
public DateTime SysStartTime { get; set; }
public DateTime SysEndTime { get; set; }
public TxtID TxtIDDescription { get; set; }
public ICollection<Feature> Feature { get; }
public ICollection<Product> Product { get; }
}
以及以下相關的上下文配置:
public virtual DbSet<Product> Product { get; set; }
public virtual DbSet<FeatureType> FeatureType { get; set; }
...
modelBuilder.Entity<Product>(entity =>
{
entity.ToTable("Product", CoreSchema)
.HasKey(k => new { k.Id })
.HasName("PK_Product");
entity.Property(a => a.Id).HasColumnName("id");
entity.Property(a => a.Name).HasColumnName("name").IsRequired();
entity.Property(a => a.Type).HasColumnName("type").HasMaxLength(50).IsRequired().IsUnicode(false);
entity.Property(e => e.SysStartTime).HasColumnName("SysStartTime").ValueGeneratedOnAddOrUpdate();
entity.Property(e => e.SysEndTime).HasColumnName("SysEndTime").ValueGeneratedOnAddOrUpdate();
entity.HasOne(p => p.FeatureType)
.WithMany(d => d.Product)
.HasForeignKey(p => p.Type)
.OnDelete(DeleteBehavior.Restrict);
});
modelBuilder.Entity<FeatureAttributeSet>(entity =>
{
entity.ToTable("FeatureAttributeSet", "Core")
.HasKey(e => new { e.Id })
.HasName("PK_FeatureAttributeSet");
entity.Property(e => e.Id).HasColumnName("id").IsRequired();
entity.Property(e => e.AttributeSetId).HasColumnName("as_id").IsRequired();
entity.Property(e => e.FeatureId).HasColumnName("feature_id").IsRequired();
entity.Property(e => e.SysStartTime).ValueGeneratedOnAddOrUpdate();
entity.Property(e => e.SysEndTime).ValueGeneratedOnAddOrUpdate();
entity.HasOne(d => d.AttributeSet)
.WithMany(p => p.FeatureAttributeSet)
.HasForeignKey(d => d.AttributeSetId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("FK_FeatureAttributeSet_AttributeSet");
entity.HasOne(d => d.Feature)
.WithMany(p => p.FeatureAttributeSet)
.HasForeignKey(d => d.FeatureId)
.OnDelete(DeleteBehavior.Restrict)
.HasConstraintName("FK_FeatureAttributeSet_Feature");
});
解決方法是配置PrincipalKey。 PrincipalKey 將允許我們定義具有唯一限制的引用鍵,這將是關系的目的地。 所以你可以像這樣使用
modelBuilder.Entity<Product>(entity =>
{
entity.ToTable("Product", CoreSchema)
.HasKey(k => new { k.Id })
.HasName("PK_Product");
entity.Property(a => a.Id).HasColumnName("id");
entity.Property(a => a.Name).HasColumnName("name").IsRequired();
entity.Property(a => a.Type).HasColumnName("type").HasMaxLength(50).IsRequired().IsUnicode(false);
entity.Property(e => e.SysStartTime).HasColumnName("SysStartTime").ValueGeneratedOnAddOrUpdate();
entity.Property(e => e.SysEndTime).HasColumnName("SysEndTime").ValueGeneratedOnAddOrUpdate();
entity.HasOne(p => p.FeatureType)
.WithMany(d => d.Product)
.HasPrincipalKey(p => p.Type)
.HasForeignKey(p => p.Type)
.OnDelete(DeleteBehavior.Restrict);
});
您在 model 構建器語句中為.HasForeignKey(p => p.Type)
中的 Product 的 FeatureType 指定的外鍵必須與 FeatureType 的主鍵類型相同。 因為 FeatureType 的 Id 屬性是一個 Guid,所以 Product 上的 Type 也必須是 Guid 類型才能用作與 FeatureType 關系的外鍵。
是否有不能將Type屬性的類型更改為 Guid 的原因?
您可以在 EF 中使用值轉換model 。
第一步是更改Product.Type
的類型:
public class Product
{
public Guid Id { get; set; }
public string Name { get; set; }
public DateTime SysStartTime { get; set; }
public DateTime SysEndTime { get; set; }
public Guid Type { get; set; } // <= Guid, not string
public FeatureType FeatureType { get; }
}
這滿足了 EF 的要求,即主鍵和外鍵屬性應該具有相同的類型。
但僅此一項就會生成 SQL ,因為數據庫類型不同而引發異常。 這就是價值轉換有用的地方。 只需在OnModelCreating
中添加一行:
entity.ToTable("Product")
.HasKey(k => new { k.Id })
.HasName("PK_Product");
// To convert string value from the database:
entity.Property(e => e.Type).HasConversion<string>();
...
現在 EF 接受關聯,並且還知道如何為查詢和插入生成正確的 SQL。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.