EF Code First外键关系
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了EF Code First外键关系相关的知识,希望对你有一定的参考价值。
我有以下情况:
- 我有一些帐户和一些游戏桌。
- 每个游戏表都有一个创建者。
- 每个帐户都可以坐在桌子上(但不必)。
我的模型类看起来像这样:
public class GameTable
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id
{
get;
set;
}
[Required]
public string Name { get; set; }
[Required]
public string Description { get; set; }
public Guid CreatorId { get; set; }
[ForeignKey(nameof(CreatorId))]
public Account Creator { get; set; }
}
public class Account
{
public Account()
{
Elo = 1000;
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
[MaxLength(15)]
[MinLength(4)]
public string Name { get; set; }
[Required]
[MaxLength(32)]
[MinLength(32)]
public string PasswordHash { get; set; }
public int Elo { get; set; }
public bool IsAdmin { get; set; }
public Guid? CurrentTableId { get; set; }
[ForeignKey(nameof(CurrentTableId))]
public virtual GameTable CurrentTable { get; set; }
}
我的上下文目前看起来像这样:
[Export(typeof(MyDbContext)), PartCreationPolicy(CreationPolicy.Shared)]
[DbConfigurationType(typeof(mysqlEFConfiguration))]
public class MyDbContext : DbContext
{
public MyDbContext() : base("DbContextCon")
{
Database.SetInitializer<PiksenDbContext>(new CreateDatabaseIfNotExists<PiksenDbContext>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
public virtual DbSet<Account> Accounts { get; set; }
public virtual DbSet<SecurityToken> SecurityTokens { get; set; }
public virtual DbSet<GameTable> GameTables { get; set; }
}
不幸的是,它不适用于这样的外键设置。以下消息让我目前感到头疼:
System.InvalidOperationException:'无法确定类型'namespace.GameTable'和'namespace.Account'之间关联的主要结尾。必须使用关系流畅API或数据注释显式配置此关联的主要结尾。
但是,当我评论其中一个FK关系时,一切都很好。这两者之间似乎存在某种冲突。
我试图获得的结果是Account
中的一个可以为空的FK,称为CurrentTableId
,而GameTable
中的一个不可为空的FK称为CreatorId
。
答案
在FK关系的每一侧,您(通常应该)具有导航属性。当存在多个FK关系时,您可以使用InversePropertyAttribute指定一对导航属性表示的FK。
例如
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ef62test
{
class Program
{
public class GameTable
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id
{
get;
set;
}
[Required]
public string Name { get; set; }
[Required]
public string Description { get; set; }
public Guid CreatorId { get; set; }
[ForeignKey(nameof(CreatorId))]
public Account Creator { get; set; }
[InverseProperty(nameof(Account.CurrentTable))]
public ICollection<Account> CurrentPlayers { get; } = new HashSet<Account>();
}
public class Account
{
public Account()
{
Elo = 1000;
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
[MaxLength(15)]
[MinLength(4)]
public string Name { get; set; }
[Required]
[MaxLength(32)]
[MinLength(32)]
public string PasswordHash { get; set; }
public int Elo { get; set; }
public bool IsAdmin { get; set; }
public Guid? CurrentTableId { get; set; }
[ForeignKey(nameof(CurrentTableId))]
public virtual GameTable CurrentTable { get; set; }
[InverseProperty(nameof(GameTable.Creator))]
public ICollection<GameTable> CreatedTables { get; } = new HashSet<GameTable>();
}
public class MyDbContext : DbContext
{
public MyDbContext() : base("DbContextCon")
{
Database.SetInitializer<MyDbContext>(new CreateDatabaseIfNotExists<MyDbContext>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
public virtual DbSet<Account> Accounts { get; set; }
//public virtual DbSet<SecurityToken> SecurityTokens { get; set; }
public virtual DbSet<GameTable> GameTables { get; set; }
}
static void Main(string[] args)
{
Database.SetInitializer(new DropCreateDatabaseAlways<MyDbContext>());
using (var db = new MyDbContext())
{
db.Database.CreateIfNotExists();
}
Console.WriteLine("Hit any key to exit.");
Console.ReadKey();
}
}
}
另一答案
它接缝你想要创建一个自我参考GameTable表。为此,您需要将一个Collection属性添加到Account表中,例如..
public virtual ICollection<GameTable> Children { get; set; }
整个代码块看起来像
public class GameTable
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id
{
get;
set;
}
[Required]
public string Name { get; set; }
[Required]
public string Description { get; set; }
public Guid CreatorId { get; set; }
[ForeignKey(nameof(CreatorId))]
public Account Creator { get; set; }
}
public class Account
{
public Account()
{
Elo = 1000;
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
[MaxLength(15)]
[MinLength(4)]
public string Name { get; set; }
[Required]
[MaxLength(32)]
[MinLength(32)]
public string PasswordHash { get; set; }
public int Elo { get; set; }
public bool IsAdmin { get; set; }
public Guid? CurrentTableId { get; set; }
[ForeignKey(nameof(CurrentTableId))]
public virtual GameTable CurrentTable { get; set; }
public virtual ICollection<GameTable> Children { get; set; }
}
希望它能解决你的问题。
以上是关于EF Code First外键关系的主要内容,如果未能解决你的问题,请参考以下文章