Постоянный список того же класса - PullRequest
0 голосов
/ 04 октября 2018

Как кто-то, переходящий из 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;}
}

Однако я не уверен, как продолжать это настаивать.Я видел статьи об Иерархическом управлении данными и пытался их реализовать, но безуспешно.Все прошло нормально, пока мне не пришлось запросить «Список», я получал рекурсивную ошибку, которую я точно не помню, что это было.

Я также искал в stackoverflow, но не мог точно определить свойпроблема.

TL; DR

Я хочу сохранить класс, у которого есть свой список, в Entity Framework / .Net Core, как мне поступить об этом?

IБуду очень признателен, если кто-нибудь сможет мне помочь!Заранее спасибо.

1 Ответ

0 голосов
/ 05 октября 2018

Проблема с вашей реализацией заключается в том, что вы не описываете свою схему в 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.Кроме того, лучше, чтобы вы имели полный контроль над созданием сценария и не позволяли многим воображению 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.

...