【问题标题】:Self referencing entity framework model自引用实体框架模型
【发布时间】:2016-01-04 01:29:15
【问题描述】:

提前感谢您的帮助。

我正在尝试为一个小 rpg 和一个朋友创建一个数据库。到目前为止,我们一直在跟踪 JSON 文件中的攻击类型等内容(我的朋友不精通技术,所以我们很早就在纯文本文件上妥协了)。我想让他成为一个网站,以便他可以更轻松地编辑我们的想法之间的关系(类型、怪物种类、可能的攻击等)

所以我从中提取的数据如下所示:

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

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

我做了一个将 JSON 转换为对象的东西,我最终得到了类似的东西:

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 个 monsterTypes 坐在一起,它们互相引用都很棒。

我正在使用这个项目来自学 MVC 和实体框架(代码优先?),虽然我过去曾像 Flask 一样玩过,但我在 C#.net 的土地上有点离谱所以如果我遗漏了一些非常明显的东西,请原谅我。

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

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

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

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

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

【问题讨论】:

  • 先设计数据库,再设计代码模型,可以极大地改进您的架构。很难看出您的代码模型应该如何映射到数据库结构。 (不是所有型号都可以)
  • @SamAxe 我认为你是对的 - 我现在先制作 4 张桌子。一个用来保存名称和 isElement,3 用来描述与 FK 的weakTo、defendAgainst 和immunoTo 关系回到第一个表。我已经修改了我的代码,并将继续设计数据库,然后相应地填写数据。我会尝试另找时间学习更多关于 Entity Framework 的知识(我感觉我已经学会了一些)

标签: c# json entity-framework


【解决方案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,则在上面的代码中将 .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]);

希望我理解正确!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-19
    • 1970-01-01
    • 2021-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多