Entity Framework Core不喜欢在启用延迟加载的情况下对虚拟外键导航属性使用自定义集访问器。它在启动/配置期间引发运行时异常。不过,每次设置其中一个属性时,我都希望运行一些自定义代码。有没有什么办法让EF Core不会对我大喊大叫?以下代码示例/说明:
public class CoilUnit
{
[Key]
public Guid Id { get; set; }
[ForeignKey("project")]
public virtual CoilProject Project { get; set; }
}
public class CoilProject
{
[Key]
public Guid Id { get; set; }
}
上面的设置在EF Core中运行得很好,但它没有达到我想要的效果。
这就是我想要的:
public class CoilUnit
{
[Key]
public Guid Id { get; set; }
private CoilProject project;
[ForeignKey("project")]
public virtual CoilProject Project
{
get { return project; }
set { project = value; /* Other code here */ }
}
}
public class CoilProject
{
[Key]
public Guid Id { get; set; }
}
在代码方面,这是我想要的,但EF Core不喜欢它,并且在我这样做的时候无法运行。
在这种情况下,有没有办法既吃蛋糕又吃蛋糕?有什么方法可以让/* Other Code */
正常运行,同时让EF Core随心所欲?
谢谢。
问题与延迟加载和自定义属性setter无关,而是后台字段和影子FK属性名称之间的冲突。
应用于导航特性时,ForeignKey
属性指定FK特性名称。如果不存在这样的属性,EF Core将使用该名称创建阴影属性。
使用auto属性,后台字段名称由编译器生成,并且是而不是"project"
,因此没有问题。但在第二种情况下,已经有一个名为"project"
的字段,因此EF Core决定这是该属性指定的FK属性。但它当然不是,也不是预期的类型(Guid
或Guid?
(,因此出现了异常。
如果使用传统的FK属性/列名(如ProjectId
(,则不需要该属性,也不会出现问题。我确信您不关心shadow属性名称,而是关心表列名。
因此,解决问题的一种方法是删除ForeignKey
属性,并使用fluent API配置FK列名:
private CoilProject project;
public virtual CoilProject Project
{
get { return project; }
set { project = value; /* Other code here */ }
}
和
modelBuilder.Entity<CoilUnit>()
.Property<Guid?>(nameof(CoilUnit.Project) + "Id")
.HasColumnName("project");
另一种方法是保留属性,但将导航属性backing字段重命名为其他支持的模式之一,例如"_project"
:
private CoilProject _project;
[ForeignKey("project")]
public virtual CoilProject Project
{
get { return _project; }
set { _project = value; /* Other code here */ }
}
您可以使用其他属性来保留您的构建逻辑,EF不会映射这些属性。
public class CoilUnit
{
[Key]
public Guid Id { get; set; }
private CoilProject project;
[ForeignKey("project")]
public virtual CoilProject Project { get; set; }
[NotMapped]
public virtual CoilProject ProjectNotMapped
{
get { return project; }
set { project = value; /* Other code here */ }
}
}
没有getter或setter的附加属性也不会被映射链接:
public virtual CoilProject ProjectNotMapped
{
set { project = value; /* Other code here */ }
}