自引用实体框架模型

时间:2016-01-04 01:29:15

标签: c# json entity-framework

先谢谢你的帮助。

我试图和朋友一起制作一个小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但是它缺少免费提交,弱访问和保护反对列I&amp; #39; d期待,我认为这是因为这都是自我指涉的。

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

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()上的错误:

  

违反了多重性约束。角色   &#39; monsterType_defendAgainst_Source&#39;关系   &#39; ParseMonsterYaml.monsterType_defendAgainst&#39;具有多重性1或   0..1。

我不确定为什么会出现这个问题?

它还创建了一个很棒的桌子,但这些列并没有真正符合我的期望:

name, isElement, monsterType_name, monsterType_name1, monsterType_name2

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

我做错了什么?有什么根本的吗?我遇到了可怕的事吗?还有更好的方法吗?

1 个答案:

答案 0 :(得分:1)

当您需要自定义列名称时,您必须告诉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,那么在上面的代码中用.HasOptional替换.HasRequired,如下所示

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]);

希望我明白这一点!