![](/img/trans.png)
[英]Use an auto-generated UNIQUEIDENTIFIER that is NOT a part of the primary key
[英]Entity Framework Core: use auto-generated foreign key as part of composite primary key
我有一個通用的 class TimeSeries<T>
,其中包含通用 state 變量State<T>
的列表。 State<T>
在某個時間包含 state。
public class TimeSeries<T>
{
[Key]
public int ID { get; set; }
public List<State<T>> States { get; set; }
}
public class State<T>
{
[Key]
public int StateID { get; set; }
public DateTime Date { get; set; }
public T State { get; set; }
}
此外,我有兩個類IntClass
和FloatClass
,它們都包含時間序列,但類型不同。 為了獲得 TimeSeries 的兩個表,其中一個有一個指向IntClass
的外鍵,另一個有一個指向FloatClass
的外鍵,我從TimeSeries<T>
派生了另外兩個類,每個類都包含一個外鍵屬性。
public class IntTimeSeries : TimeSeries<int>
{
public int IntClassID{ get; set; }
}
public class FloatTimeSeries : TimeSeries<float>
{
public int FloatClassID{ get; set; }
}
IntClass
和FloatClass
包含派生類的實例:
public class IntClass
{
[Key]
public int ID { get; set; }
public IntTimeSeries TimeSeries { get; set; }
}
public class FloatClass
{
[Key]
public int ID { get; set; }
public FloatTimeSeries TimeSeries { get; set; }
}
此方法生成表State<int>
和State<float>
等。 它們分別具有(自動生成的)外鍵IntClassID
和FloatClassID
。 如果像我在這里所做的那樣用[Key]
注釋StateID
,那么這當然是主鍵。
然而,我想要的是主鍵分別是復合(Date, IntClassID)
和(Date, FloatClassID)
。 我需要這個,因為有時我需要從我只有讀取權限的第二個數據庫更新值。 這可能嗎?
在 EF-core 3 和 5 中,您可以通過修改 EF 的元數據來實現這一點,這些元數據在這些更高版本中很容易訪問:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var stateTypes = modelBuilder.Model.GetEntityTypes()
.Where(e => e.ClrType.IsConstructedGenericType
&& e.ClrType.GetGenericTypeDefinition() == (typeof(State<>)))
.ToList();
stateTypes
.ForEach(t => t.SetPrimaryKey(t.FindProperties(new[] { "StateID", "Date"} )));
}
這首先收集從State<>
派生的實體類型,然后設置這些類型的主鍵屬性。 使用nameof
當然會使這更加運行時安全。
對於 EF core 2 用戶,最后一條語句是:
stateTypes.ForEach(t => t.SetPrimaryKey(t.GetProperties()
.Where(p => new[] { "StateID", "Date" }.Contains(p.Name))
.OrderByDescending(p => p.Name)
.ToList()));
( OrderByDescending
因為在這種情況下,屬性不是按數組的順序獲取的)。
感謝 Gert,我找到了解決方案:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var stateTypes = modelBuilder.Model.GetEntityTypes()
.Where(e => e.ClrType.IsConstructedGenericType
&& e.ClrType.GetGenericTypeDefinition() == (typeof(State<>)))
.ToList();
stateTypes.ForEach(t => t.FindProperty(GeneratedForeignKeyName(t)).IsNullable = false);
stateTypes
.ForEach(t => t.SetPrimaryKey(t.FindProperties(new[] { GeneratedForeignKeyName(t), "Date"} )));
}
private string GeneratedForeignKeyName(IMutableEntityType t)
{
if (t.Name.Equals(/* data type namespace here */ + ".State<float>"))
{
return "FloatClassID";
}
else if (t.Name.Equals(/* data type namespace here */ + ".State<int>"))
{
return "IntClassID";
}
else throw new ArgumentException();
}
在 .NET 7 中,使用新的 PrimaryKey 屬性現在更容易。 將生成為字符串的外鍵傳遞給它,實體框架將執行 rest。
[Table("Likes")]
[PrimaryKey("LikedId", "LikedById")]
public sealed class DataUserLike
{
// Columns
public required DataUser Liked { get; init; }
public required DataUser LikedBy { get; init; }
}
https://learn.microsoft.com/en-us/ef/core/modeling/keys?tabs=data-annotations#tabgroup_2
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.