Entity framework EF core 3使用没有声明性引用完整性的数据库
当我的主数据库没有任何FK时,我们是否有一种简单的方法在代码模型中创建关系,仅用于在我的服务中使用导航或包含在LINQ中!它是由一个旧程序使用的旧数据库,所以我不能在SQL中添加FK ou PK。我使用Scaffold检索我的表:Entity framework EF core 3使用没有声明性引用完整性的数据库,entity-framework,entity-framework-core,Entity Framework,Entity Framework Core,当我的主数据库没有任何FK时,我们是否有一种简单的方法在代码模型中创建关系,仅用于在我的服务中使用导航或包含在LINQ中!它是由一个旧程序使用的旧数据库,所以我不能在SQL中添加FK ou PK。我使用Scaffold检索我的表: public partial class UsagerEw { public string Code { get; set; } public string Nom { get; set; } public string Email { get
public partial class UsagerEw
{
public string Code { get; set; }
public string Nom { get; set; }
public string Email { get; set; }
public string ModeLogin { get; set; }
public string Role { get; set; }
public string ParamRole { get; set; }
public string EmpContact { get; set; }
public byte RestreintCommContrat { get; set; }
public byte RestreintProjet { get; set; }
public string Password { get; set; }
public byte Inactif { get; set; }
public byte Administrateur { get; set; }
public string PasswordTemp { get; set; }
public DateTime? PasswordTempExp { get; set; }
public int CodeInt { get; set; }
public int? IdSuperviseur { get; set; }
public byte? EstSuperviseur { get; set; }
public byte? LectureSeule { get; set; }
public byte? DoitChangerPw { get; set; }
public string PermsGrps { get; set; }
public string ParamRole2 { get; set; }
public Guid? Adguid { get; set; }
}
public partial class RefreshToken
{
public int Id { get; set; }
public int UserId { get; set; }
public string Token { get; set; }
public DateTime Expires { get; set; }
public DateTime Created { get; set; }
public string CreatedByIp { get; set; }
public DateTime? Revoked { get; set; }
public string RevokedByIp { get; set; }
public string ReplaceByToken { get; set; }
}
我在考虑使用流畅的代码创建“模型方”关系,如:
modelBuilder.Entity<RefreshToken>(entity =>
{
entity.Property(e => e.CreatedByIp)
.IsRequired()
.HasMaxLength(50);
entity.Property(e => e.ReplaceByToken).HasMaxLength(400);
entity.Property(e => e.RevokedByIp).HasMaxLength(50);
entity.Property(e => e.Token)
.IsRequired()
.HasMaxLength(400);
entity.HasOne<UsagerEw>(r => r.UsagerEW).WithMany(u => u.RefreshTokens).HasForeignKey(r => r.UsagerEWId);
});
来匹配我流畅的关系。我得到:SqlException:无效的列名“UsagerEWId”
但我想我需要手动添加一些虚拟属性
实体表?这是一个正确的方法吗
如果不打算使用延迟加载,则不需要为属性添加virtual
。
脚手架生成部分类,所以只需在同一模型的项目的其他文件中创建相同的类,并添加所需的导航属性
脚手架将其添加到OnModelCreating中,但如果我理解正确,
当我将代码迁移回DB时调用此函数
不,为了正确工作,EF调用了这个函数来配置模型,您需要这个调用。如果您不添加迁移或通过EF函数重新创建数据库,例如context.database.EnsureCreated()
,则不会发生任何Schama更改。
因此,
OnModelCreating
函数很重要。如果下一个Scaffold删除了您的代码-您必须以某种方式将其返回(不是EF方面的大专家,也许社区可以提出更好的解决方案)。实体框架需要配置一个键,以了解如何唯一地标识行。这实际上不需要是表上的主键,它可以由可以唯一区分行和行的列组成。因此,在您的USAGREW表中,如果电子邮件在用户之间是唯一的(他们登录的方式),那么可以将其定义为密钥,即使它不是数据库中的PK。如果它采用列的组合,则可以将all定义为键并指定列顺序。(即使用电子邮件和代码)
导航属性用于实体到实体的关系。这些对于LINQ查询在实体之间建立关系(FK)非常有用,因此您可以在实体之间进行查询,而无需显式连接表达式。如果你只关心关系,它们是可选的
例如,如果我有一个订单,并且订单有一个订单状态:
我可以将订单定义为:
public class Order
{
[Key]
public int OrderId { get; set; }
// ...
[ForeignKey("OrderStatus")]
public int OrderStatusId { get; set; }
public OrderStatus Status { get; set; }
}
通过这种方式,我可以在订单中加载OrderStatus:
var order = context.Orders.Include(x => x.OrderStatus).Single(x => x.OrderId == orderId);
。。。这样我就可以获得OrderStatus属性,比如order.OrderStatus.Name
。导航属性不需要是虚拟的
,但这意味着如果我尝试访问OrderStatus而不立即加载它(`.Include(x=>x.OrderStatus)),那么我可能会得到一个NullReferenceException。如果EF碰巧缓存了OrderStatus,它将填充OrderStatus。这可能会导致一些不一致和有条件的异常
通过将属性声明为virtual
,如果我们忘记使用Include
并访问该属性,EF将在必要时再次转到DB,前提是Order对象仍在其DbContext的范围内。(上下文未处理)这有助于避免意外的异常,但如果滥用,通常会对性能造成重大影响。(懒散的负载)
默认情况下,我建议将属性声明为虚拟属性,因为通常最好知道代码应该一致地工作(并调查性能问题),而不是让它在异常不一致的情况下可能失败。总的来说,我建议使用Linq投影来填充视图模型/DTO,使用Select
哪个EF将自动组成相关连接,而无需急加载或延迟加载
如果我们真的不关心通过订单从OrderStatus访问属性,我们可以只映射FK,而不使用导航属性。对于OrderStatus之类的东西,我们可以使用一个enum
,它在代码中具有足够的描述性,如果只有少数几个状态,这些状态可以由应用程序预加载和缓存,以便在需要时查询,如描述等
public class Order
{
[Key]
public int OrderId { get; set; }
//...
public int OrderStatusId { get; set; }
}
对于现有数据库的配置,您有3个选项:
DbContext.OnModelCreating
IEntityTypeConfiguration
实现类并将它们注册到DbContext.OnModelCreating
对于简单模式和EF管理模式,属性通常就足够了,modelBuilder处理非默认内容。对于具有大量关系的更大或更复杂的模式,我更喜欢使用
IEntityTypeConfiguration
,因为它有助于保持配置的有序性。Ok,但我尝试在OnMOdelCreating中设置一个断点,然后在startup.cs文件中使用服务实例化我的上下文。AddDbContext(…),然后使用和一个对DB的小查询。从未调用断点。您认为使用include和virtual属性会对性能产生很大影响吗?您更喜欢使用JOIN吗?仅仅拥有虚拟或其他导航属性本身不会对性能产生任何影响。人们被抓住的地方不是有意就是无意地依赖于惰性加载。(导致“急切加载所有内容”和/或“关闭延迟加载”等决策)如果您在选择时正确使用投影,则导航属性将导致非常高效且性能良好的查询/w它们各自的连接将自动为您完成。我默认确保nav属性是虚拟的,以避免异常,我使用分析器进行调试,这有助于突出显示查询问题。我试图添加导航属性,但出现了错误。见第1版。有什么建议吗?感谢实体中的字段需要映射到数据表中的列。RefreshToken有一个UserId列,但不清楚这是如何实现的
var order = context.Orders.Include(x => x.OrderStatus).Single(x => x.OrderId == orderId);
public class Order
{
[Key]
public int OrderId { get; set; }
//...
public int OrderStatusId { get; set; }
}