Entity framework 首先使用EF核心代码,不使用外键
我正在尝试使用EF Core 2.1设计一个应用程序,使用代码优先的方法,但我不希望数据库中有外键。我发现FKs真的很难处理,尤其是在尝试运行Entity framework 首先使用EF核心代码,不使用外键,entity-framework,foreign-keys,migration,code-first,ef-core-2.1,Entity Framework,Foreign Keys,Migration,Code First,Ef Core 2.1,我正在尝试使用EF Core 2.1设计一个应用程序,使用代码优先的方法,但我不希望数据库中有外键。我发现FKs真的很难处理,尤其是在尝试运行dotnet ef数据库drop时。运行此命令时出错,因为我的数据库中有外键 我不想担心外键,只想为相关项创建具有Id属性的表。如果/当我需要相关信息时,我将从数据库中获取相关项目 public class Employer : BaseEntity { public string Name { get; set; }
dotnet ef数据库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; }
}
公共类雇主:基本实体
{
公共字符串名称{get;set;}
公共字符串说明{get;set;}
公共ICollection雇员{get;set;}
公共ICollection客户端{get;set;}
}
公共类雇员:BaseEntity
{
公共字符串名{get;set;}
公共字符串LastName{get;set;}
公共EmployeeType EmployeeType{get;set;}
公共Guid EmployerId{get;set;}
公共雇主{get;set;}
}
公共类客户端:BaseEntity
{
公共字符串名称{get;set;}
public int EmployerId{get;set;}
公共雇主{get;set;}
}
使用关系数据库时,数据库中的每个对象都需要一个Id,如果该对象“属于”不同表中的另一个对象,则需要一个外键。你不能没有它
幸运的是,实体框架足够聪明,如果设计得当,很少使用外键执行(组)连接。您通常使用虚拟属性
在实体框架中,类表示数据库的表。表中的列由类的非虚拟属性表示。虚拟属性表示类之间的关系
因此,您有一些基本实体
和三种特殊类型的基本实体
:雇主
,员工
和客户
每个雇主
都有零名或多名员工
;每个员工
只有一个雇主
:一对多的简单关系。为此,每个员工
都需要其所属的雇主
的外键,无论您喜欢与否。幸运的是,你不必使用它
类似地,在雇主
和客户
之间存在一对多关系:每个雇主
都有零个或多个客户
,每个客户
都只属于一个雇主
,使用外键
使用实体时,您的类需要稍作更改:表之间的关系应标记为虚拟
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),而是想要一个平面结果(更像一个连接),请从子对象开始:
给我他们雇主的所有(或部分)客户
实体框架知道您设计了一对多,并将为您进行适当的连接
请注意,如果没有客户,您将无法找到雇主。我不希望数据库中有外键,您是认真的吗?仅仅因为删除数据库更容易?(无论如何,这听起来不太可能)。谁来保护数据完整性?我仍然可以使用没有FKs的数据库。我可以使用连接或单独调用进行SQL调用并获取信息。数据库中的“我的项目”之间仍将存在关系,它们只是不会由外键关联。我们是否有可能要对数据库进行查询,但表中没有外键。我想说的是,没有外键的数据库表只在使用ef core时有用,而不是直接从sql管理工具查询?是的,这是可能的。连接是在值的相似性上完成的。例如,产品可能位于城市中的仓库中。客户也住在城市里。客户可能想知道他想要的产品是否在家乡的宜家。你将加入城市。但也有问题:布鲁塞尔是否等于布鲁塞尔/布鲁塞尔?要解决这个问题,您需要创建一个包含城市的表,其中每个城市都有一个主键和一个已知名称(外键)列表。现在连接在CityId 10上完成。其优点是没有主键/外键,而主键/外键不会exist@HaraldCoppoolse:“你不能没有它。”这不是真的。几乎所有的ERP系统都没有外键。我目前使用的Dynamics Nav没有外键,而MES系统也有外键。缺少外键并没有造成任何问题,而当您不得不手动使用DML语句时,MES系统是一个真正的难题。我目前也在考虑编写一个没有外键的EF应用程序,因为它们真的很麻烦。如果你知道这在EF中不可能/不合理的原因,我很想听听,但一般来说这是非常可能的。很好,你可以拥有没有外键的数据库。但是你需要一些信息来定义“许多”项目属于哪个项目,不是吗?当我使用外键这个术语时,我指的是这个引用值。除了这样的参考值,您还有其他方法吗?
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(),
});
var result = dbContext.Clients.Select(client => new
{
Id = client.Id,
Name = client.Name,
...
Employer = new
{
Id = client.Employer.Id,
...
},
});