EF Code First外键关系

时间:2017-12-17 12:32:38

标签: c# mysql entity-framework 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:&#39;无法确定主体   类型&namespace; GameTable&#39;之间关联的结束和   &#39; namespace.Account&#39 ;.这种关联的主要目的必须是   使用关系流畅的API或数据显式配置   注释&#39;

然而,当我评论其中一个FK-Relationships时,一切都很好。这两者之间似乎存在某种冲突。

我想要获得的结果是名为Account的{​​{1}}中的一个可以为空的FK,以及CurrentTableId中名为GameTable的不可为空的FK。

2 个答案:

答案 0 :(得分:1)

在FK关系的每一侧,您(通常应该)具有导航属性。当存在多个FK关系时,您可以使用InversePropertyAttribute指定一对导航属性所代表的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();
        }
    }
}

答案 1 :(得分:0)

您希望创建自引用 GameTable 表。 为此,您需要将Collection属性添加到帐户表,如..

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

希望它能解决你的问题。