保留相同的列表 Class

Persist List of same Class

作为从 JPA 转到 C# .Net 和 Entity framework 的人,我很难理解 EF 中缺乏对列表的支持。

我需要做以下事情:

public class Foo {

   public long Id {get; set;}

   //Class value objects / attributes
   //e.g
   public string Name {get; set;}
   public AnotherFoo AFoo {get; set;}

   //This class can have many children classes of the same type
   //In this case Foo can have many Foo's
   public List<Foo> {get; set;}
}

但是,我不确定如何继续坚持下去。我看过有关分层数据管理的文章,并尝试实施它们但没有成功。一切顺利,直到我不得不查询 'List' 然后,我会得到一个递归错误,我不记得它到底是什么。

我也在 Whosebug 中搜索过,但无法查明我的问题。

TL;DR

我想保留一个 class,它在 Entity Framework /.Net Core 中有一个自己的列表,我将如何处理它?

如果有人能帮我解决这个问题,我将不胜感激!提前致谢。

您的实现的问题是您没有向 Entity Framework 描述您的模式,即您没有定义对象之间的关系。

这是一个可行的建议:

public class Foo
{
    public int ID { get; set; }
    public string Name { get; set; }

    [ForeignKey("AFoo")]
    public int? AFooID { get; set; }
    public virtual AnotherFoo AFoo { get; set; }

    public int? ParentID { get; set; }
    public virtual Foo Parent { get; set; }
    public virtual List<Foo> Children { get; set; } = new List<Foo>();
}

public class AnotherFoo
{
    public int ID { get; set; }
    public string Name { get; set; }
}

请注意以下几点:

  • 我已将外键 属性 AFooID 添加到 AFoo 实体。 Entity Framework 将自行识别 AFoo 属性 和 Foo 实体之间的关系,并且在构建模式时它还会向 AntoherFoo 实体添加一个外键。但是这个键在您的代码中将不可用,因为您没有将它添加到 Foo class 属性中。另外,你最好能完全控制 scema 的创建,不要让 Entity Framework 的想象力过多(不过这很好)。
  • A 在 AFooID 上添加了注释 [ForeignKey("AFoo")] 以定义这是 AFoo 导航参数的外键。通常我还应该在 ID 上添加一个类似的注释以将其定义为主键,但是 Entity Framework 会自动为名为 ID.[=53= 的整数 属性 执行此操作]
  • 我在所有导航参数上使用了 virtual 关键字以允许延迟加载这些参数。

现在,关于你的主要问题;您可以创建相同类型的子项的引用,就好像它是任何其他类型一样。但是你必须描述关系!在此示例中,我配置了一对多关系,这意味着每个 foo 只能有一个父项但有多个子项。为此,我使用了 Fluent API:

public class MyContext: DbContext
{
    public DbSet<Foo> Foos { get; set; }
    public DbSet<AnotherFoo> AFoos { get; set; }

    public MyContext()
        : base("TestDB")
    {
        Configuration.LazyLoadingEnabled = true;
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Foo>()
            .HasOptional(f => f.Parent)
            .WithMany(f => f.Children)
            .HasForeignKey(f => f.ParentID)
            .WillCascadeOnDelete(false);
    }
}

覆盖 DbContext class 的 OnModelCreating 方法以指定更多 "fluently" 您的数据库架构。

现在 运行 在您的程序包管理器控制台中使用以下命令来创建您的数据库:

  1. add-migration InitialDB 它将创建一个描述要创建的模式的 cs 文件。检查是否符合您的要求。
  2. update-database 它将使用您的配置文件中定义的连接字符串和上述文件中的模式创建一个数据库。

运行 这个演示应用程序:

    static void Main(string[] args)
    {
        var foo = new Foo { Name = "parent foo" };
        var foo1 = new Foo { Name = "first foo child" };
        var foo2 = new Foo { Name = "second foo child" };
        foo.Children.Add(foo1);
        foo.Children.Add(foo2);

        using(var context = new MyContext())
        {
            context.Foos.Add(foo);
            context.SaveChanges();
        }
        // another transaction to read the saved data
        using(var context = new MyContext())
        {
            var readfoo = context.Foos.FirstOrDefault();
            Console.WriteLine($"{readfoo.Name} has the following children:");
            foreach(var child in readfoo.Children)
                Console.WriteLine(child.Name);
        }

        Console.ReadKey();
    }

结果符合预期:

希望我能帮助你解决问题,让你对Entity Framework的世界有更多的了解。