持续列出相同类别的

时间:2018-10-04 19:09:37

标签: c# .net entity-framework relational-database

作为一个从JPA到C#.Net和Entity框架的人,我很难克服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;}
}

但是,我不确定如何继续坚持下去。我看过有关分层数据管理的文章,我尝试实现它们,但没有成功。一切正常,直到我不得不查询“列表”,然后我会得到一个递归错误,我不记得是什么。

我也在stackoverflow中进行了搜索,但是无法查明我的问题。

TL; DR

我想在Entity Framework /.Net Core中保留一个具有自身列表的类,我将如何进行呢?

如果有人可以帮助我,我将非常感激!预先感谢。

1 个答案:

答案 0 :(得分:2)

实现的问题是您没有向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实体。实体框架将自行识别AFoo属性与Foo实体之间的关系,并且在构建架构时,它还将向AntoherFoo实体添加外键。但是该键在您的代码中将不可用,因为您没有将其添加到Foo类属性中。另外,最好是对scema的创建有完全的控制权,并且不要让Entity Framework的想象力太大(尽管这是相当不错的)。
  • A在[ForeignKey("AFoo")]上添加了注释AFooID,以定义这是AFoo导航参数的外键。通常,我还应该在ID上添加类似的注释,以将其定义为主键,但是Entity Framework会自动对名为ID的整数属性执行此操作。
  • 我在所有导航参数上都使用了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);
    }
}

重写OnModelCreating类的DbContext方法,以更“流畅地”指定数据库架构。

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

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

结果符合预期:

enter image description here

希望我能帮助您解决问题,并进一步了解Entity Framework的世界。