EF Core 索引器属性(Indexer property)场景及应用

简介

EF Core 中的索引器属性(Indexer Property)是指通过一个特殊的属性来访问实体类中的数据,而不必明确声明实体属性。这种属性在一些动态或未预定义的场景中非常有用,比如当实体的属性名在编译时并不确定,或者属性名集合较大时。

场景及应用

1.动态属性访问

索引器属性最常见的应用场景是动态属性访问。这在处理 JSON 数据或其他半结构化数据时尤其有用。例如,当你有一个属性名称集合在编译时并不确定,或者从外部源(如配置文件、API 响应等)中获取属性名时,可以使用索引器属性来动态访问这些属性。

2.字典数据结构

如果实体类包含一个字典类型的属性,可以通过索引器属性来访问字典中的数据。例如,如果你的实体中包含了一个 Dictionary<string, object> 来存储额外的数据,使用索引器属性可以简化访问这些数据的方式。

public class DynamicEntity
{
private Dictionary<string, object> _additionalData = new Dictionary<string, object>(); public object this[string key]
{
get => _additionalData.ContainsKey(key) ? _additionalData[key] : null;
set => _additionalData[key] = value;
}
}

3.元数据处理

在一些应用场景中,需要将不同的元数据存储在实体中而不增加额外的列。在这种情况下,可以使用索引器属性来处理这些元数据。例如,当你需要根据业务逻辑在数据库表中存储额外的、可变的属性集合时,可以使用索引器属性来管理这些属性。

4.简化代码

索引器属性可以简化代码,减少显式声明属性的需求。在开发过程中,减少了重复代码,提高了代码的可维护性和灵活性。

EF Core 配置

在 EF Core 中使用索引器属性时,需要在模型配置阶段进行一些特殊的配置,以确保 EF Core 正确地将索引器属性映射到数据库字段。这里我们讨论几种常见的配置方法。

1. 使用 Dictionary<string, object> 的索引器属性

如果你在实体类中使用了 Dictionary<string, object> 作为索引器属性的存储机制,并希望 EF Core 将这些键值对存储在数据库表的专用列中,可以按照以下方式配置:

实体类示例

public class Product
{
public int Id { get; set; }
public string Name { get; set; } private Dictionary<string, object> _extendedProperties = new Dictionary<string, object>(); public object this[string key]
{
get => _extendedProperties.ContainsKey(key) ? _extendedProperties[key] : null;
set => _extendedProperties[key] = value;
}
}

OnModelCreating 方法中配置

DbContext 中的 OnModelCreating 方法中配置索引器属性。你可以使用 OwnsMany 来配置字典的映射。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>()
.OwnsMany(p => p._extendedProperties, a =>
{
a.Property<string>("Key");
a.Property<string>("Value");
a.WithOwner().HasForeignKey("ProductId");
a.ToTable("ProductExtendedProperties");
});
}

此配置将 Product 实体的扩展属性存储在一个单独的表 ProductExtendedProperties 中,该表将有三列:ProductIdKeyValue

2. 直接将索引器属性映射到表的列

如果你希望直接将索引器属性映射到表的列(而不是将字典存储在单独的表中),你可以使用 Property 方法来配置。

实体类示例

public class MultilingualContent
{
private Dictionary<string, string> _translations = new Dictionary<string, string>(); public int Id { get; set; } public string this[string language]
{
get => _translations.ContainsKey(language) ? _translations[language] : null;
set => _translations[language] = value;
}
}

OnModelCreating 方法中配置

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MultilingualContent>()
.Property(e => e["en"])
.HasColumnName("EnglishContent"); modelBuilder.Entity<MultilingualContent>()
.Property(e => e["fr"])
.HasColumnName("FrenchContent");
}

这种配置将索引器属性中不同语言的内容直接映射到 MultilingualContent 表中的不同列(如 EnglishContentFrenchContent)。

3. 映射到 JSON 列

EF Core 5.0 开始支持将复杂类型映射到 JSON 列中。如果你使用索引器属性存储复杂对象,可以将其映射为 JSON。

实体类示例

public class Configuration
{
private Dictionary<string, string> _settings = new Dictionary<string, string>(); public int Id { get; set; } public string this[string key]
{
get => _settings.ContainsKey(key) ? _settings[key] : null;
set => _settings[key] = value;
}
}

OnModelCreating 方法中配置

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Configuration>()
.Property(e => e._settings)
.HasColumnType("jsonb")
.HasColumnName("Settings");
}

这种配置将整个字典映射为一个 JSON 字段,可以灵活存储复杂和动态的数据结构。

完整实例之-多语言支持

在处理多语言支持的案例中,配置好 EF Core 后,你可以通过索引器属性动态地访问和更新不同语言的内容。下面将详细说明如何调用和请求使用这个多语言支持的模型。

1. 设置数据库上下文和实体

首先,假设你已经按照前面的指导配置好了 MultilingualContent 实体和数据库上下文。这里是完整的实体类和上下文的代码:

实体类 MultilingualContent

public class MultilingualContent
{
private Dictionary<string, string> _translations = new Dictionary<string, string>(); public int Id { get; set; } public string this[string language]
{
get => _translations.ContainsKey(language) ? _translations[language] : null;
set => _translations[language] = value;
}
}

数据库上下文 AppDbContext

public class AppDbContext : DbContext
{
public DbSet<MultilingualContent> MultilingualContents { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MultilingualContent>()
.Property(e => e["en"])
.HasColumnName("EnglishContent"); modelBuilder.Entity<MultilingualContent>()
.Property(e => e["fr"])
.HasColumnName("FrenchContent"); // 配置其他语言...
}
}

2. 添加数据

假设你需要为一段内容添加英语和法语版本。你可以使用索引器属性来设置这些语言的内容。

using (var context = new AppDbContext())
{
var content = new MultilingualContent();
content["en"] = "Hello, world!";
content["fr"] = "Bonjour, le monde!"; context.MultilingualContents.Add(content);
context.SaveChanges();
}

上面的代码会在数据库中插入一条记录,其中包含英语和法语的文本。

3. 检索数据

假设你想要根据语言检索某段内容。可以使用索引器属性来获取相应语言的文本。

using (var context = new AppDbContext())
{
var content = context.MultilingualContents.FirstOrDefault(c => c.Id == 1); if (content != null)
{
string englishText = content["en"];
string frenchText = content["fr"]; Console.WriteLine($"English: {englishText}");
Console.WriteLine($"French: {frenchText}");
}
}

这段代码会从数据库中检索 ID 为 1 的内容,并输出其英语和法语版本。

4. 更新数据

你可以使用索引器属性来更新某个语言的内容。

using (var context = new AppDbContext())
{
var content = context.MultilingualContents.FirstOrDefault(c => c.Id == 1); if (content != null)
{
content["en"] = "Hello, everyone!";
content["fr"] = "Bonjour, tout le monde!"; context.SaveChanges();
}
}

这段代码会更新 ID 为 1 的内容,将英语和法语文本分别更新为新的内容。

5. 删除数据

删除操作和普通的实体一样,可以使用 EF Core 提供的标准方法。

using (var context = new AppDbContext())
{
var content = context.MultilingualContents.FirstOrDefault(c => c.Id == 1); if (content != null)
{
context.MultilingualContents.Remove(content);
context.SaveChanges();
}
}

这段代码会从数据库中删除 ID 为 1 的内容及其所有语言版本的文本。

总结

EF Core 的索引器属性对于处理动态属性、元数据、或结构化但不固定的属性集合非常有用。它能够提高代码的灵活性和可维护性,特别是在处理需要存储可变属性的场景时。

END 欢迎关注 "ShareFlow" 公众号

EF Core 索引器属性(Indexer property)场景及应用的更多相关文章

  1. 【Unity|C#】基础篇(7)——属性(Property)/ 索引器(Indexer)

    [学习资料] <C#图解教程>(第6章):https://www.cnblogs.com/moonache/p/7687551.html 电子书下载:https://pan.baidu.c ...

  2. 雷林鹏分享:C# 索引器(Indexer)

    C# 索引器(Indexer) 索引器(Indexer) 允许一个对象可以像数组一样被索引.当您为类定义一个索引器时,该类的行为就会像一个 虚拟数组(virtual array) 一样.您可以使用数组 ...

  3. EF Core反向导航属性解决多对一关系

    多对一是一种很常见的关系,例如:一个班级有一个学生集合属性,同时,班级有班长.语文课代表.数学课代表等单个学生属性,如果定义2个实体类,班级SchoolClass和学生Student,那么,班级Sch ...

  4. EF Core中Key属性相同的实体只能被跟踪(track)一次

    在EF Core的DbContext中,我们可以通过DbContext或DbSet的Attach方法,来让DbContext上下文来跟踪(track)一个实体对象,假设现在我们有User实体对象,其U ...

  5. EF Core忽略某个属性保存

    1.事情起因 某天朋友突然问我他的EF不能保存,让我帮忙看看,观察发现主表中存在明细表的集合,导致保存失败. 2.解决方案 方案1:DTO模型与DO模型分开,保存时映射. 分层领域模型规约名词解释: ...

  6. 把C#对象变成数组技术---索引器(indexer)

    public class IndexerDemo { IList list = new List(); public IndexerDemo() { list.Add("); list.Ad ...

  7. set,get方法(属性,索引器)

    很多时候我们不可以把一些字段暴露出来允许别人调用和修改,为了隐藏这些字段又便于加限制的使用,在面向对象编程中一般采用写get set函数的办法,比如: //字段_age, "_"表 ...

  8. C#索引器-有参属性

    总结 只要类中有类似于属性的元素就应创建索引器,此属性代表的不是一个值,而是值的集合,其中每一个项由一组参数标识. 这些参数可以唯一标识应引用的集合中的项. 索引器延伸了属性的概念,索引器中的一个成员 ...

  9. EF Core 的关联查询

    0 前言 本文会列举出 EF Core 关联查询的方法: 在第一.二.三节中,介绍的是 EF Core 的基本能力,在实体中配置好关系,即可使用,且其使用方式,与编程思维吻合,是本文推荐的方式. 第四 ...

  10. EF Core 2.0 已经支持自动生成父子关系表的实体

    现在我们在SQL Server数据库中有Person表如下: CREATE TABLE [dbo].[Person]( ,) NOT NULL, ) NULL, ) NULL, ) NULL, [Cr ...

随机推荐

  1. vue中手写table的升降序

    有些时候,我们总是无可避免的需要自己去手撸一些东西,因为需求总是在不断的变化.例如,最开始的需求,我们只是在首页展示一个数据列表,此时,我们可能直接就自己手写了一个table,后来,突然增加了一个需求 ...

  2. Nginx+Fail2ban 实现同一ip在一分钟内连续三次请求同一接口并响应成功时进行封禁

    1. 安装 Fail2Ban 和 Nginx 如果尚未安装 Fail2Ban 和 Nginx,可以使用以下命令进行安装: # CentOS默认的仓库中可能不包含Nginx,所以需要添加EPEL(Ext ...

  3. 【基础整理】Mapping representation 机器人所用地图种类及相关介绍

    参考与前言 本文主要介绍 建图 Mapping 方面的一些 基础知识介绍与相关下游任务使用 涉及知识较为基础,SLAM大佬们可以提前退出了 主要针对应用为移动机器人与物流无人驾驶车:提前申明:大部分文 ...

  4. SpringBoot集成MQTT

    MQTT介绍 MQTT 是基于 Publish/Subscribe(发布/订阅) 模式的物联网通信协议,凭借简单易实现.支持 QoS.报文小等特点. 其具有协议简洁.⼩巧.可扩展性强.省流量.省电等优 ...

  5. Lambda表达式常见用法

    Lambda介绍 Lambda,别名函数式编程 函数式编程是一种编程范式.它把计算当成是数学函数的求值,从而避免改变状态和使用可变数据.它是一种声明式的编程范式,通过表达式和声明而不是语句来编程. L ...

  6. docker-compose的使用和常用命令

    Docker简介 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows操作系统的机器上,也可以实现虚拟化. ...

  7. Linux服务器从头配置

    安装配置jdk 下载 jdk jdk-8u171-linux-x64.tar.gz 将该压缩包放到/usr/local/jdk目录下然后解压(jdk目录需要自己手动创建) tar zxvf jdk-8 ...

  8. Display、Visibility 和 Opacity 的区别

    <style> .d1{ display: none; } .d2{ visibility: visible; } .d3{ opacity: 0; } </style> &l ...

  9. 深入理解 Vue 3 组件通信

    在 Vue 3 中,组件通信是一个关键的概念,它允许我们在组件之间传递数据和事件.本文将介绍几种常见的 Vue 3 组件通信方法,包括 props.emits.provide 和 inject.事件总 ...

  10. vue 拖拉改变盒子高度(mousedown、mousemove、mouseup)流畅不卡顿

    需求:上下两个盒子之间添加可拖拽按钮,实现高度变化 html: <textarea :id="'mycode'+(index*1+1)" :ref="'mycode ...