Как скрыть автоматически увеличенное свойство при создании модели в Entity Framework code-first - PullRequest
0 голосов
/ 16 июня 2019

В Entity Framework я создал класс Department, который имеет автоматически увеличенные значения DepartmentId и ICollection, равные Employees.

Я не хочу, чтобы кто-то видел эти два свойства при создании объекта класса Department. Кто-нибудь может помочь?

Я пытался использовать модификатор доступа, но это не сработало.

public class Department
{
    public int DepartmentId { get; set; }

    public string DepartmentName { get; set; }

    public ICollection<Employee> Employees { get; set; }
}


using (var ctx = new EmployeeContext())
{
    var department = new Department()
        {
                DepartmentName = "Engineering",
        };

    ctx.Departments.Add(department);
    ctx.SaveChanges();
}

Когда пользователь делает

var department = new Department()

затем department.DepartmentId и department.Employees не должны быть доступны.

Ответы [ 3 ]

0 голосов
/ 16 июня 2019

Вы можете использовать функцию полей поддержки.

Базовое ядро ​​Entity Framework

public class Department
{
    private int _departmentId { get; set; }

    public string DepartmentName { get; set; }

    private ICollection<Employee> _employees { get; set; }
}

public class Employee
{
    private int _employeeId { get; set; }

    public Department Department;
}

и теперь в вашем DbContext классе

protected override void OnModelCreating(ModelBuilder modelBuilder)
{

    modelBuilder.Entity<Department>().HasKey("_departmentId");
    modelBuilder.Entity<Department>().Property<int>("_departmentId");
    modelBuilder.Entity<Department>(c =>
        c.HasMany(typeof(Employee), "_employees")
            .WithOne("Department")
    );

    modelBuilder.Entity<Employee>().HasKey("_employeeId");

    base.OnModelCreating(modelBuilder);
}

Структура объекта 6.2.0

public class Employee
{
    private int _employeeId { get; set; }

    public Department Department { get; set; }

    public class EmployeeConfiguration : EntityTypeConfiguration<Employee>
    {
        public EmployeeConfiguration()
        {
            HasKey(d => d._employeeId);
        }
    }
}

public class Department
{
    private int _departmentId { get; set; }

    public string DepartmentName { get; set; }

    private ICollection<Employee> _employees { get; set; }

    public class DepartmentConfiguration : EntityTypeConfiguration<Department>
    {
        public DepartmentConfiguration()
        {
            HasKey(d => d._departmentId);
            Property(d => d._departmentId);
            HasMany(d => d._employees).WithOptional(e => e.Department);
        }
    }
}

и теперь в вашем DbContext классе

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{

    modelBuilder.Configurations
        .Add(new Department.DepartmentConfiguration())
        .Add(new Employee.EmployeeConfiguration());

    base.OnModelCreating(modelBuilder);
}

Я пробовал этот код, и он работает.

0 голосов
/ 17 июня 2019

Вспомогательные поля являются опцией, однако я не рекомендую их для PK, поскольку вы, вероятно, захотите иметь возможность выбирать данные по PK, и PK не будет открыт для объекта. Например, вы можете проверить дочерние данные, используя:

var employeesInDepartment = context.Employees
    .Where(x => x.Department.DepartmentId == departmentId)
    .ToList()

или

var employeesInDepartment = context.Departments
    .Where(x => x.DepartmentId == departmentId)
    .SelectMany(x => x.Employees)
    .ToList();

Это будет недоступно, если ваш идентификатор отдела полностью скрыт. Вы можете использовать .Find, который будет использовать сопоставленный PK, однако это менее практично, поскольку Find всегда будет загружать объект, где Select может быть более избирательным в отношении данных, которые вы хотите получить. Вы также захотите, чтобы PK отправляли в пользовательский интерфейс, чтобы вы могли связать данные, возвращающиеся к их соответствующим объектам во время обратной поездки. Например, когда я создаю нового сотрудника, он будет связан с отделом. Я отправляю обратно DepartmentID для ассоциированных, а не отсоединенных объектов. Отправка сущностей - это ловушка производительности и безопасности, и даже если вы захотите сериализовать сущности между собой, частные вспомогательные поля не будут перенесены, поэтому при возвращении сущности Департамента не будет никакого PK, что делает его бесполезным.

Вместо того, чтобы пытаться скрыть собственность, вы можете охранять сеттеров, делая их личными.

public class Department
{
    public int DepartmentId { get; private set; }
    // ...
    public virtual ICollection<Employee> Employees { get; private set; } = new List<Employee>();
}

Таким образом, вы все равно можете воспользоваться преимуществами доступа к этим свойствам в выражениях Linq, не предполагая, что они могут быть установлены. Ссылки на коллекции никогда не должны выставлять сеттеры, чтобы избежать проблем, когда кто-то пытается очистить дочернюю коллекцию, устанавливая коллекцию в новый список.

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

0 голосов
/ 16 июня 2019

Если я правильно понимаю, когда вы хотите достичь, это абстракция POCO Department Class.

Ну, вы можете попробовать создать ViewModel, например:

public class DepartmentViewModel
{
    public string DepartmentName { get; set; }
}

Затем покажите или получите базу данных на основе этого ViewModel. Однако, если вы хотите получить объект POCO из вашего, например, метода Dbset.Find() или наоборот, вам необходимо заполнить базу объектов на другом объекте ИЛИ использовать мапперы, такие как как AutoMapper. Допустим, у вас есть объект из DepartmentViewModel с именем vm, как показано ниже:

var vm = new DepartmentViewModel(); //<---- this is an example
var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<DepartmentViewModel, Department>();
});
IMapper mapper = config.CreateMapper();
//entity is a POCO Department Object. 
var entity = mapper.Map<DepartmentViewModel, Department>(vm);
//here you can pass the entity to EF for insert. 
using (var ctx = new EmployeeContext())
{
    ctx.Departments.Add(entity);
    ctx.SaveChanges();
}

Тогда, как объяснено, вы можете легко сопоставить его с помощью Automapper, поскольку вы можете видеть, что entity теперь ваш Department object, и вы можете сделать наоборот, изменив DepartmentViewModel с помощью Department в конфигурации.

И не забудьте скачать AutoMapper из nuget:

Install-Package AutoMapper - Версия 8.1.1

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...