Entity Framework 复合键映射
Entity Framework Composite Keys Mapping
我的数据库中有 2 个 table:
游戏:
public class Game
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[ForeignKey("WinningSlot"), Column(Order = 0)]
public int Id { get; set; }
public int numer { get; set; }
public string md5 { get; set; }
public string secret { get; set; }
public GameStatus Status { get; set; }
public int SlotsNumber { get; set; }
public DateTime CreationTime { get; set; }
public DateTime? EndDime { get; set; }
public DateTime? ForceEndTime { get; set; }
[ForeignKey("WinningSlot"), Column(Order = 1)]
public int WinningSlotId { get; set;
public GameSlot WinningSlot { get; set; }
public double SlotPrice { get; set; }
public List<GameSlot> Slots { get; set; }
}
游戏机:
public class GameSlot
{
[Column(Order = 0), Key]
public int GameId { get; set; }
[ForeignKey("GameId")]
public Game Game { get; set; }
[Column(Order = 1), Key]
public int Slot { get; set; }
public int? PlayerId { get; set; }
[ForeignKey("PlayerId")]
public WotUser Player { get; set; }
public string SecretData { get; set; }
}
如您所见,GameSlot
table 的 PK 是复合的,由 GameID
(也是 Game
的 FK)和 Slot
组成(这是插槽号)。一切正常,直到我尝试将 WinningSlot
属性 添加到我的 Game
table。它在数据库更新时在 GameSlot
table 中为其生成另一个 Game_Id
列。
我所有试图弄乱流利 api 的尝试都失败了。你能帮我建立一个正常的关系吗? winningslot
列是可选的,可以为空。谢谢!
更新:
使用 FluentApi 解决的问题:
modelBuilder.Entity<Game>()
.HasOptional(g => g.WinningSlot)
.WithMany()
.HasForeignKey(g => new { g.Id, g.WinningSlotId });
但这是另一个:
当我尝试添加这样的插槽时(示例代码),它工作正常:
var game = db.Games.Find(1);
game.WinningSlotId = 1;
db.SaveChanges();
但是如果我想改为设置插槽:
var game = db.Games.Find(1);
var gameslot = db.Slots.Find(game.Id, 1);
game.WinningSlot = gameslot;
db.SaveChanges();
它会抛出异常告诉我我不能修改游戏的 Id 属性。如果 gameslot 的 gameID = game.Id?
有什么问题
你可以试试这个:
modelBuilder.Entity<GameSlot>()
.HasKey(g => new { g.GameID, g.Slot })
.HasRequired(g => g.Game)
.WithMany(g => g.GameSlot);
编辑:我发现了为什么要创建索引,您需要将导航属性设为虚拟。因此,您不需要我上面写的流利的 api,但我个人认为流利的映射比使用数据注释更清晰,就像您所做的那样,不会使您的模型与属性混淆。
public class Game
{
public Game()
{
Slots = new HashSet<GameSlot>();
}
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[ForeignKey("WinningSlot"), Column(Order = 0)]
public int Id { get; set; }
public int numer { get; set; }
public string md5 { get; set; }
public string secret { get; set; }
public GameStatus Status { get; set; }
public int SlotsNumber { get; set; }
public DateTime CreationTime { get; set; }
public DateTime? EndDime { get; set; }
public DateTime? ForceEndTime { get; set; }
[ForeignKey("WinningSlot"), Column(Order = 1)]
public int WinningSlotId { get; set;
public double SlotPrice { get; set; }
public virtual GameSlot WinningSlot { get; set; }
public virtual ICollection<GameSlot> Slots { get; set; }
}
(将接口与哈希集一起用于您的导航集合属性更为常见。)
此外,如果您希望 Game
可以从 GameSlot
访问,或者通过 lazy/eager 加载,您将必须添加导航 属性 到 Game
也是,但在旁注中。
关于你遇到的第二个错误,Game.Id
既是Game
的主键又是GameSlot
的外键。如果您尝试指定另一个 winningslot 进行游戏,那么您也在尝试更改 GameSlot
的 ID。
我的数据库中有 2 个 table:
游戏:
public class Game
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[ForeignKey("WinningSlot"), Column(Order = 0)]
public int Id { get; set; }
public int numer { get; set; }
public string md5 { get; set; }
public string secret { get; set; }
public GameStatus Status { get; set; }
public int SlotsNumber { get; set; }
public DateTime CreationTime { get; set; }
public DateTime? EndDime { get; set; }
public DateTime? ForceEndTime { get; set; }
[ForeignKey("WinningSlot"), Column(Order = 1)]
public int WinningSlotId { get; set;
public GameSlot WinningSlot { get; set; }
public double SlotPrice { get; set; }
public List<GameSlot> Slots { get; set; }
}
游戏机:
public class GameSlot
{
[Column(Order = 0), Key]
public int GameId { get; set; }
[ForeignKey("GameId")]
public Game Game { get; set; }
[Column(Order = 1), Key]
public int Slot { get; set; }
public int? PlayerId { get; set; }
[ForeignKey("PlayerId")]
public WotUser Player { get; set; }
public string SecretData { get; set; }
}
如您所见,GameSlot
table 的 PK 是复合的,由 GameID
(也是 Game
的 FK)和 Slot
组成(这是插槽号)。一切正常,直到我尝试将 WinningSlot
属性 添加到我的 Game
table。它在数据库更新时在 GameSlot
table 中为其生成另一个 Game_Id
列。
我所有试图弄乱流利 api 的尝试都失败了。你能帮我建立一个正常的关系吗? winningslot
列是可选的,可以为空。谢谢!
更新: 使用 FluentApi 解决的问题:
modelBuilder.Entity<Game>()
.HasOptional(g => g.WinningSlot)
.WithMany()
.HasForeignKey(g => new { g.Id, g.WinningSlotId });
但这是另一个: 当我尝试添加这样的插槽时(示例代码),它工作正常:
var game = db.Games.Find(1);
game.WinningSlotId = 1;
db.SaveChanges();
但是如果我想改为设置插槽:
var game = db.Games.Find(1);
var gameslot = db.Slots.Find(game.Id, 1);
game.WinningSlot = gameslot;
db.SaveChanges();
它会抛出异常告诉我我不能修改游戏的 Id 属性。如果 gameslot 的 gameID = game.Id?
有什么问题你可以试试这个:
modelBuilder.Entity<GameSlot>()
.HasKey(g => new { g.GameID, g.Slot })
.HasRequired(g => g.Game)
.WithMany(g => g.GameSlot);
编辑:我发现了为什么要创建索引,您需要将导航属性设为虚拟。因此,您不需要我上面写的流利的 api,但我个人认为流利的映射比使用数据注释更清晰,就像您所做的那样,不会使您的模型与属性混淆。
public class Game
{
public Game()
{
Slots = new HashSet<GameSlot>();
}
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[ForeignKey("WinningSlot"), Column(Order = 0)]
public int Id { get; set; }
public int numer { get; set; }
public string md5 { get; set; }
public string secret { get; set; }
public GameStatus Status { get; set; }
public int SlotsNumber { get; set; }
public DateTime CreationTime { get; set; }
public DateTime? EndDime { get; set; }
public DateTime? ForceEndTime { get; set; }
[ForeignKey("WinningSlot"), Column(Order = 1)]
public int WinningSlotId { get; set;
public double SlotPrice { get; set; }
public virtual GameSlot WinningSlot { get; set; }
public virtual ICollection<GameSlot> Slots { get; set; }
}
(将接口与哈希集一起用于您的导航集合属性更为常见。)
此外,如果您希望 Game
可以从 GameSlot
访问,或者通过 lazy/eager 加载,您将必须添加导航 属性 到 Game
也是,但在旁注中。
关于你遇到的第二个错误,Game.Id
既是Game
的主键又是GameSlot
的外键。如果您尝试指定另一个 winningslot 进行游戏,那么您也在尝试更改 GameSlot
的 ID。