EF Core 3.1.7 只读属性
EF Core 3.1.7 Read Only Properties
我正在扩展我的基本 EF 模型,添加一个复合 class 主机,它依赖于其他四个主机,BlockedIp、MxRecord、SmtpGeoLocation、MailExchanger,主机与其他主机之间的关系是 1:1 因为它们被模型中的其他实体使用。我希望主机将这些其他 class 中的 属性 值的抽象反映为布尔值只读属性。示例 IsPrivateIp、HasDnsRecord、IsBlocked、HasGeoLocation、HasMailExchanger、HasMxRecord。
依赖的class BlockedIp例如,有一个bool IsBlocked 属性没有保存到DB,它的值是基于一个枚举,后面是一个涉及模式匹配的过程规则 select 适当的枚举值。
public partial class BlockedIp
{
private string patternMatch = IpPatternMatching.None.ToString();
public int? BlockedIpId { get; set; }
public string IpAddress { get; set; }
public string IpBlockType
{
get
{
return this.patternMatch;
}
set
{
if (value == IpPatternMatching.AllPatterns.ToString())
this.patternMatch = value;
else if (value == IpPatternMatching.DoubleBlock.ToString())
this.patternMatch = value;
else if (value == IpPatternMatching.SingleIP.ToString())
this.patternMatch = value;
else if (value == IpPatternMatching.SingleBlock.ToString())
this.patternMatch = value;
else if (value == IpPatternMatching.TrippleBlock.ToString())
this.patternMatch = value;
else
this.patternMatch = IpPatternMatching.None.ToString();
}
}
public Host Host { get; set; }
public int? HostId { get; set; }
[NotMapped]
public bool IsBlocked
{
get
{
if (this.IpBlockType == IpPatternMatching.AllPatterns.ToString())
return true;
else if (this.IpBlockType == IpPatternMatching.DoubleBlock.ToString())
return true;
else if (this.IpBlockType == IpPatternMatching.SingleBlock.ToString())
return true;
else if (this.IpBlockType == IpPatternMatching.SingleIP.ToString())
return true;
else if (this.IpBlockType == IpPatternMatching.TrippleBlock.ToString())
return true;
else
return false;
}
}
主机class,另一方面,会将这些抽象的属性值保存到数据库中,但由于它们依赖于其他classes中的值,因此它们需要是只读的。主机看起来像这样,其抽象值为 IsBlocked:
public partial class Host
{
public int HostId { get; set; }
public string HostDomain { get; set; }
public string HostIP { get; set; }
public string HostName { get; set; }
public bool IsBlocked
{
get
{
return this.BlockedIp.IsBlocked;
}
set { }
}
public BlockedIp BlockedIp { get; set; }
public MxRecord MxRecord { get; set; }
public SmtpGeoLocation SmtpGeolocation { get; set; }
public MailExchanger MailExchanger { get; set; }
}
当我添加创建主机的迁移时,EF 抱怨 IsBlocked 没有 setter,所以我很不情愿地在 class 中添加了一个空的 setter。 EF 接受了这个并且应用程序运行了,但在我的直觉中,我忍不住相信,这样一个轻率的选择最终会回来困扰我。我更喜欢更实用或更优雅的东西,但在尝试了一天半的替代品后却一无所获。
在我的模型构建器中,我确实找到了对 Metadata.SetPropertyAccessMode 的引用,如下所示:
entity.Property(e => e.IsBlocked)
.HasColumnName("IsBlocked")
.HasColumnType<bool>("bit")
.IsRequired(true)
.Metadata.SetPropertyAccessMode(PropertyAccessMode.PreferProperty);
我可以将 bool IsBlocked setter 映射到一种方法,该方法执行将 bool 值与 IP 地址相匹配所需的繁重工作,映射到这些枚举值之一,但这将是很多努力扭转已经确立的过程。
我还没有读过一篇文章,它充分解释了 Metadata.SetPropertyAccessMode 以及其他值,足以让我知道我是否正在通过使用它走上正确的道路。希望这里有人提出了对 EF Core 中只读 属性 的需求,并可以提供替代方案。
可以使用Backing Fields for this, which also helps explain what the PropertyAccessMode是。
read-only 属性 在 SQL 中的正确表示是计算列。但是你说你不想走那条路
当您将某些内容保存到数据库时,EF Core(以及几乎所有其他人)都希望您事后阅读它。因此所有 C# 属性必须是 read-write - 否则任何 ORM 都无法填充它们(我们不会考虑目前的构造函数参数:-))。即使对于计算属性 - 您也必须将它们从数据库中提取到 C# 世界。
所以除了 setter.
,我真的看不到任何其他选择
我尝试将支持字段与模型构建器元标记结合使用。Metadata.SetPropertyAccessMode,并简单地忽略了直接应用于 setter 的任何值。
entity.Property(e => e.IsBlocked)
.HasColumnName("IsBlocked")
.HasColumnType<bool>("bit")
.IsRequired(true)
.Metadata.SetPropertyAccessMode(PropertyAccessMode.PreferProperty);
有一个没有数据 table 支持的 属性,通过 EF 导航 属性 获取这些值,让它反映相关 table 中的值,证明比简单地对数据库进行非规范化并将相同的数据保留两个 table 更努力。 EF 无需处理滚动您自己的数据访问对象的繁琐工作,从而使这项任务变得完全轻松。感谢您在正确方向上的推动...
我正在扩展我的基本 EF 模型,添加一个复合 class 主机,它依赖于其他四个主机,BlockedIp、MxRecord、SmtpGeoLocation、MailExchanger,主机与其他主机之间的关系是 1:1 因为它们被模型中的其他实体使用。我希望主机将这些其他 class 中的 属性 值的抽象反映为布尔值只读属性。示例 IsPrivateIp、HasDnsRecord、IsBlocked、HasGeoLocation、HasMailExchanger、HasMxRecord。
依赖的class BlockedIp例如,有一个bool IsBlocked 属性没有保存到DB,它的值是基于一个枚举,后面是一个涉及模式匹配的过程规则 select 适当的枚举值。
public partial class BlockedIp
{
private string patternMatch = IpPatternMatching.None.ToString();
public int? BlockedIpId { get; set; }
public string IpAddress { get; set; }
public string IpBlockType
{
get
{
return this.patternMatch;
}
set
{
if (value == IpPatternMatching.AllPatterns.ToString())
this.patternMatch = value;
else if (value == IpPatternMatching.DoubleBlock.ToString())
this.patternMatch = value;
else if (value == IpPatternMatching.SingleIP.ToString())
this.patternMatch = value;
else if (value == IpPatternMatching.SingleBlock.ToString())
this.patternMatch = value;
else if (value == IpPatternMatching.TrippleBlock.ToString())
this.patternMatch = value;
else
this.patternMatch = IpPatternMatching.None.ToString();
}
}
public Host Host { get; set; }
public int? HostId { get; set; }
[NotMapped]
public bool IsBlocked
{
get
{
if (this.IpBlockType == IpPatternMatching.AllPatterns.ToString())
return true;
else if (this.IpBlockType == IpPatternMatching.DoubleBlock.ToString())
return true;
else if (this.IpBlockType == IpPatternMatching.SingleBlock.ToString())
return true;
else if (this.IpBlockType == IpPatternMatching.SingleIP.ToString())
return true;
else if (this.IpBlockType == IpPatternMatching.TrippleBlock.ToString())
return true;
else
return false;
}
}
主机class,另一方面,会将这些抽象的属性值保存到数据库中,但由于它们依赖于其他classes中的值,因此它们需要是只读的。主机看起来像这样,其抽象值为 IsBlocked:
public partial class Host
{
public int HostId { get; set; }
public string HostDomain { get; set; }
public string HostIP { get; set; }
public string HostName { get; set; }
public bool IsBlocked
{
get
{
return this.BlockedIp.IsBlocked;
}
set { }
}
public BlockedIp BlockedIp { get; set; }
public MxRecord MxRecord { get; set; }
public SmtpGeoLocation SmtpGeolocation { get; set; }
public MailExchanger MailExchanger { get; set; }
}
当我添加创建主机的迁移时,EF 抱怨 IsBlocked 没有 setter,所以我很不情愿地在 class 中添加了一个空的 setter。 EF 接受了这个并且应用程序运行了,但在我的直觉中,我忍不住相信,这样一个轻率的选择最终会回来困扰我。我更喜欢更实用或更优雅的东西,但在尝试了一天半的替代品后却一无所获。
在我的模型构建器中,我确实找到了对 Metadata.SetPropertyAccessMode 的引用,如下所示:
entity.Property(e => e.IsBlocked)
.HasColumnName("IsBlocked")
.HasColumnType<bool>("bit")
.IsRequired(true)
.Metadata.SetPropertyAccessMode(PropertyAccessMode.PreferProperty);
我可以将 bool IsBlocked setter 映射到一种方法,该方法执行将 bool 值与 IP 地址相匹配所需的繁重工作,映射到这些枚举值之一,但这将是很多努力扭转已经确立的过程。
我还没有读过一篇文章,它充分解释了 Metadata.SetPropertyAccessMode 以及其他值,足以让我知道我是否正在通过使用它走上正确的道路。希望这里有人提出了对 EF Core 中只读 属性 的需求,并可以提供替代方案。
可以使用Backing Fields for this, which also helps explain what the PropertyAccessMode是。
read-only 属性 在 SQL 中的正确表示是计算列。但是你说你不想走那条路
当您将某些内容保存到数据库时,EF Core(以及几乎所有其他人)都希望您事后阅读它。因此所有 C# 属性必须是 read-write - 否则任何 ORM 都无法填充它们(我们不会考虑目前的构造函数参数:-))。即使对于计算属性 - 您也必须将它们从数据库中提取到 C# 世界。
所以除了 setter.
,我真的看不到任何其他选择我尝试将支持字段与模型构建器元标记结合使用。Metadata.SetPropertyAccessMode,并简单地忽略了直接应用于 setter 的任何值。
entity.Property(e => e.IsBlocked)
.HasColumnName("IsBlocked")
.HasColumnType<bool>("bit")
.IsRequired(true)
.Metadata.SetPropertyAccessMode(PropertyAccessMode.PreferProperty);
有一个没有数据 table 支持的 属性,通过 EF 导航 属性 获取这些值,让它反映相关 table 中的值,证明比简单地对数据库进行非规范化并将相同的数据保留两个 table 更努力。 EF 无需处理滚动您自己的数据访问对象的繁琐工作,从而使这项任务变得完全轻松。感谢您在正确方向上的推动...