【问题标题】:EF Code First Foreign Key RelationshipEF 代码优先外键关系
【发布时间】:2018-05-31 00:12:56
【问题描述】:

我有以下情况:

  • 我有几个帐户和几个游戏桌。
  • 每个游戏桌都有一个创建者。
  • 每个帐户都可以坐在一张桌子上(但不是必须)。

我的模型类如下所示:

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”和 '命名空间.帐户'。该关联的主体端必须是 使用关系流式 API 或数据显式配置 注释。'

但是,当我注释掉其中一个 FK 关系时,一切都很好。这两者之间似乎存在某种冲突。

我试图得到的结果是Account 中的一个可空FK 称为CurrentTableIdGameTable 中的一个不可空FK 称为CreatorId

【问题讨论】:

  • 据我所知,WithRequiredPrinciple() 等不能使用 Data annotations,您必须使用 Fluent API 配置关系。
  • @DevilSuichiro 不幸的是,即使两个 guid 都可以为空并且两个导航属性都是虚拟的,它仍然给我这个错误。
  • 延迟加载的能力和列的必需/可选参数在主体/依赖帐户中无关紧要。在 0..1 到 0..1 关系(或介于两者之间的任何位置)中,您需要配置在创建的 SQL 语句中首先插入和最后删除的关系的主体端。这是导致此错误的原因,它与导航属性的“状态”无关。

标签: c# mysql entity-framework ef-code-first


【解决方案1】:

在 FK 关系的每一侧,您都可以(通常应该)拥有导航属性。而当存在多个FK关系时,可以使用InversePropertyAttribute来指定一对Navigation Properties代表哪个FK。

EG

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();
        }
    }
}

【讨论】:

  • 感谢您的回答。我想我现在明白了。我能再问你一件事吗? -> “虚拟”关键字,我用对了吗?它与可空和不可空有关吗?
  • 虚拟导航属性允许 EF 生成运行时子类型,这些属性的实现实际上将按需从数据库中获取相关实体。如果您的导航属性不是虚拟的,这称为“延迟加载”,您无法获得“延迟加载”,请参阅msdn.microsoft.com/en-us/library/…
  • 啊,右,我实际上知道这一点,但忘了这一点,现在没有完成ef几年。谢谢你。 :)
【解决方案2】:

你想创建一个自引用的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; }
    }

希望它能解决你的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-02-13
    • 2016-01-31
    • 2015-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    相关资源
    最近更新 更多