Entity framework 首先使用EF核心代码,不使用外键

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; }

我正在尝试使用EF Core 2.1设计一个应用程序,使用代码优先的方法,但我不希望数据库中有外键。我发现FKs真的很难处理,尤其是在尝试运行
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,
          ...
     },
});