Использование EF Core Code First без внешних ключей - PullRequest
0 голосов
/ 05 ноября 2018

Я пытаюсь разработать приложение, используя EF Core 2.1, используя подход, основанный на коде, но я не хочу, чтобы в моей базе данных были внешние ключи. Я считаю, что работать с ФК очень сложно, особенно когда я пытаюсь запустить dotnet ef database drop. Я получаю ошибки при выполнении этой команды, потому что в моей базе данных есть внешние ключи.

Я бы хотел не беспокоиться о внешних ключах и просто сделать таблицы со свойствами Id для связанных элементов. Я пойду и возьму соответствующий предмет из базы данных, если / когда мне понадобится эта связанная информация.

   public class Employer : BaseEntity
    {
        public string Name { get; set; }
        public string Description { get; set; }
        public ICollection<Employee> Employees { get; set; }
        public ICollection<Client> Clients { get; set; }
    }

public class Employee : BaseEntity
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public EmployeeType EmployeeType { get; set; }
    public Guid EmployerId { get; set; }
    public Employer Employer { get; set; }
}
public class Client : BaseEntity
    {
        public string Name { get; set; }
        public int EmployerId { get; set; }
        public Employer Employer { get; set; }

    }

1 Ответ

0 голосов
/ 06 ноября 2018

При использовании реляционной базы данных каждому объекту в базе данных понадобится идентификатор, а если объект «принадлежит» другому объекту в другой таблице, вам потребуется внешний ключ. Вы не можете обойтись без этого.

К счастью, сущностный каркас достаточно умен, поэтому, если вы его правильно спроектируете, вы редко будете использовать внешние ключи для выполнения (групповых) объединений. Вы обычно используете виртуальные свойства.

В структуре сущностей классы представляют таблицы вашей базы данных. Столбцы в таблицах представлены не виртуальными свойствами класса. Виртуальные свойства представляют отношения между классами.

Итак, у вас есть BaseEntity и три специальных типа BaseEntities: Employers, Employees и Clients.

Каждый Employer имеет ноль или более Employees; каждый Employee имеет ровно одно Employer: простое отношение «один ко многим». Для этого каждому Employee нужен внешний ключ к Employer, к которому он принадлежит, нравится вам это или нет. К счастью, вам не придется его использовать.

Аналогично, существует отношение «один ко многим» между Employer и Client: каждый Employer имеет ноль или более Clients, каждый Client принадлежит ровно одному Employer с использованием внешнего ключа .

Использование сущности Первый код соглашения платформы Ваши классы нуждаются в небольшом изменении: отношения между таблицами должны быть помечены как виртуальные.

class Employer : BaseEntity
{
    public int Id {get; set;}

    // every Employer has zero or more Employees:
    public virtual ICollection<Employee> Employees { get; set; }

    // every Employer has zero or more Clients:
    public virtual ICollection<Client> Clients { get; set; }

    ...
}

class Employee : BaseEntity
{
    public int Id {get; set;}

    // every Employee belongs to exactly one Employer, using a foreign key:
    public int EmployerId {get; set;}
    public virtual Employer Employer { get; set; }

    ...
}

class Client : BaseEntity
{
    public int Id {get; set;}

     // Every Client belongs to exactly one Employer, using foreign key:
     public int EmployerId { get; set; }
     public virtual  Employer Employer { get; set; }

     ...
}

Важным изменением является то, что отношения между таблицами помечены как виртуальные

Примечание. Возможно, вам не нужны целые числа для первичных ключей. Это не сильно изменит идею.

Для выполнения запросов, которые (группируют) присоединяются к таблицам, вам не нужно использовать внешние ключи,

GroupJoin

Дайте мне всех (или некоторых) работодателей со всеми (или некоторыми) из его клиентов и сотрудников.

Для этого вы бы использовали GroupJoin: каждый выбранный Работодатель имел бы подгруппу Клиентов и Сотрудников. С структурой сущностей вам не нужно делать соединение самостоятельно:

var result = dbContext.Employers    // From every employer in the sequence ofall Employers
    .Where(employer => ...)         // or only some of them
    .Select(employer => new         // make one new object
    {
        // select only the properties you actually plan to use
        Id = employer.Id,
        Name = employer.Name,

        Employees = employer.Employees
            .Where(employee => ...)         // only if you do not want all Employees
            .Select(employee => new
            {    
                 // again, select only the properties you plan to use
                 Id = employee.Id,
                 Name = employee.Name,
                 ...
            })
            .ToList(),
        Clients = employer.Clients
            .Where(client=> ...)         // only if you do not want all Clients
            .Select(client => new
            {
                 ...
            })
            .ToList(),
    });

Entity Framework знает, что вы разработали один-ко-многим, и сделает правильное соединение для вас. Хотя вы не упомянули какой-либо внешний ключ, структура сущности знает, какие внешние ключи используются.

Обратите внимание, что таким образом вы также получаете Работодателей, у которых нет Клиентов или Сотрудников

Inner Join

Если вам не нужны «объекты с его подобъектами» (GroupJoin), а плоский результат (более похожий на «Join»), начните с подобъекта:

Дайте мне всех (или некоторых) клиентов с их работодателем

var result = dbContext.Clients.Select(client => new
{
     Id = client.Id,
     Name = client.Name,
     ...

     Employer = new
     {
          Id = client.Employer.Id,
          ...
     },
});

Entity Framework знает, что вы разработали один-ко-многим, и сделает правильное соединение для вас.

Обратите внимание, что вы не получите работодателей без клиентов.

...