在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
不可用。
答案 0 :(得分:0)
如果我对要实现的目标的理解正确,那就是抽象POCO Department Class
。
例如,您可以尝试创建一个ViewModel
:
public class DepartmentViewModel
{
public string DepartmentName { get; set; }
}
然后基于此ViewModel
显示或获取数据库,但是,例如,如果要从Dbset.Find()
方法中获取POCO对象,反之亦然,则需要基于其他对象填充对象或使用诸如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
,反之亦然,您可以通过将{{1 }}。
别忘了从nuget下载AutoMapper:
安装软件包AutoMapper-版本8.1.1
答案 1 :(得分:0)
您可以使用后备字段功能。
实体框架核心
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);
}
我已经尝试过此代码,并且可以正常工作。
答案 2 :(得分:0)
可以选择支持字段,但是我不建议将它们用于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();
如果您的部门ID被完全隐藏,则此功能将不可用。您可以利用.Find
来使用映射的PK,但是,这不太实用,因为Find
将始终加载实体,其中Select
可以对要检索的数据更具选择性。您还希望PK发送到UI,以便您可以将返回旅程中返回到其各自实体的数据关联起来。例如,当我创建一个新员工时,它将与一个部门关联。我发回DepartmentID来关联,而不是断开连接的实体。发送实体是性能和安全性的陷阱,即使您确实希望在各个序列之间对实体进行序列化,也不会传输私有后备字段,因此返回的Department实体将缺少任何PK,从而使其无用。
您可以通过将其设置为私有来保护设置者,而不是试图隐藏该属性。
public class Department
{
public int DepartmentId { get; private set; }
// ...
public virtual ICollection<Employee> Employees { get; private set; } = new List<Employee>();
}
这样,您仍然可以利用在Linq表达式中访问这些属性的优势,而不必暗示可以对其进行设置。集合引用永远不要暴露setter,以免出现某些人试图通过将子集合设置为新列表来清除子集合的问题。
注意:此解决方案仍将不允许您从客户端接收实体,因为私有设置程序将防止反序列化。这是一件好事,因为这将有助于确保您的项目确实受到破坏,无法接受来自客户端的实体。我将介绍此here的含义。