自引用实体框架模型

本文关键字:模型 框架 实体 自引用 | 更新日期: 2023-09-27 18:29:01

提前感谢您的帮助。

我正试着和一个朋友为一个小rpg制作一个数据库。到目前为止,我们一直在跟踪JSON文件中的攻击类型(我的朋友不懂技术,所以我们早期只对纯文本文件进行了妥协)。我想让他成为一个网站,这样他就可以更容易地编辑我们的想法之间的关系(类型、怪物物种、可能的攻击等)

所以我从中提取的数据看起来是这样的:

{
    "name": "water", 
    "isElement": true, 
    "defendAgainst": [
      "fire", 
      "undead", 
      "atomic", 
      "food"
    ], 
    "immuneTo": [
      "water"
    ], 
    "weakTo": [
      "electric", 
      "zoetic", 
      "sonic", 
      "eldritch"
    ]
  }, ... and so on

在这个例子中,水是一种元素,它可以防御火型,对水攻击免疫,对声波攻击较弱。

我做了一个将JSON转换为Object的东西,最后得到了这样的东西:

public class monsterType
{
    [Key]
    public string name { get; set; }
    public ICollection<monsterType> weakTo { get; set; }
    public ICollection<monsterType> immuneTo { get; set; }
    public ICollection<monsterType> defendAgainst { get; set; }
    public bool isElement { get; set; }
}

我通过以下操作从JSON进行翻译:

        // set up the types references
        foreach (typeJSON ty in typeListFromFile){
            monsterType realTypeReference = lookUpMonsterTypeFromJSONtype(ty, realTypes);
            //convert those lists
            ICollection<monsterType> mtWTs = ty.weakTo.Select(w => lookUpMonsterTypeFromName(w, realTypes)).ToList();
            ICollection<monsterType> mtDAs = ty.defendAgainst.Select(w => lookUpMonsterTypeFromName(w, realTypes)).ToList();
            ICollection<monsterType> mtITs = ty.immuneTo.Select(w => lookUpMonsterTypeFromName(w, realTypes)).ToList();
            //set them on the real type reference
            realTypeReference.weakTo = mtWTs;
            realTypeReference.defendAgainst = mtDAs;
            realTypeReference.immuneTo = mtITs;
        }

数据进入monsterType的实例很好。我和40个怪物坐在一起,他们互相指代都很棒。

我正在使用这个项目来自学MVC和实体框架(代码优先?),尽管我过去曾像Flask一样玩过,但我在C#.net领域有点力不从心,所以如果我遗漏了一些明显的东西,请原谅我。

我已经建立了一个与SQL Server数据库的数据库连接,它正在创建realTypes表OK——但它缺少immuneTo、weakTo和defensedAgains列,我认为这是因为这都是自引用的。

好吧,所以我做了一个数据上下文:

public class monsterDataContext : DbContext
{
    public monsterDataContext() : base("name=blood")
    {
    }
    public DbSet<monsterType> Types { get; set; }
}

我只是循环浏览我的列表并保存我的更改:

   using (var theDB = new monsterDataContext())
   {
       foreach (monsterType ty in realTypes)
       {
           theDB.Types.Add(ty);
       }
       theDB.SaveChanges();
    }

当我这样做时,它在DB.SaveChanges()上出错,带有:

违反了多重性约束。角色关系的'monsterType_defendAgainst_Source'"ParseMonsterYaml.monsterType_defendAgainst"具有多重性1或0..1.

我不太清楚为什么这是个问题?

它还创建了表,这很好,但列并没有真正达到我的期望:

name, isElement, monsterType_name, monsterType_name1, monsterType_name2

但这并不像错误那么重要。没有数据被加载到表中,它是空的。

我做错了什么?一些基本的东西?我是不是遇到了什么可怕的事?有更好的方法吗?

自引用实体框架模型

当您想要自定义列名时,您必须告诉EF它们的名称,您可以按如下方式执行。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<MonsterType>()
                .HasRequired(t => t.DefendAgainst)
                .WithMany()
                .Map(configuration => configuration.MapKey("DefendAgainst"));
            modelBuilder.Entity<MonsterType>()
               .HasRequired(t => t.ImmuneTo)
               .WithMany()
               .Map(configuration => configuration.MapKey("ImmuneTo"));
            modelBuilder.Entity<MonsterType>()
              .HasRequired(t => t.WeakTo)
              .WithMany()
              .Map(configuration => configuration.MapKey("WeakTo"));

           base.OnModelCreating(modelBuilder);
        }

关于您的错误,默认情况下,您的一对多关系列创建为NOT NULL,这就是为什么当您保存缺少的数据时,它违反了SQL约束。如果DefendAgaint、WeekTo和ImmuneTo可以为null,那么在上面的代码中,将.HasRequired替换为.HasOptional,如下所示

protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<MonsterType>()
                .HasOptional(t => t.DefendAgainst)
                .WithMany()
                .Map(configuration => configuration.MapKey("DefendAgainst"));
            modelBuilder.Entity<MonsterType>()
               .HasOptional(t => t.ImmuneTo)
               .WithMany()
               .Map(configuration => configuration.MapKey("ImmuneTo"));
            modelBuilder.Entity<MonsterType>()
              .HasOptional(t => t.WeakTo)
              .WithMany()
              .Map(configuration => configuration.MapKey("WeakTo"));

           base.OnModelCreating(modelBuilder);
        }

这将生成此SQL

create table [dbo].[MonsterTypes] (
    [Name] [nvarchar](128) not null,
    [IsElement] [bit] not null,
    [DefendAgainst] [nvarchar](128) null,
    [ImmuneTo] [nvarchar](128) null,
    [WeakTo] [nvarchar](128) null,
    primary key ([Name])
);
alter table [dbo].[MonsterTypes] add constraint [MonsterType_DefendAgainst] foreign key ([DefendAgainst]) references [dbo].[MonsterTypes]([Name]);
alter table [dbo].[MonsterTypes] add constraint [MonsterType_ImmuneTo] foreign key ([ImmuneTo]) references [dbo].[MonsterTypes]([Name]);
alter table [dbo].[MonsterTypes] add constraint [MonsterType_WeakTo] foreign key ([WeakTo]) references [dbo].[MonsterTypes]([Name]);

希望我已经理解了这个权利!