- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
Redis是一个开源的、高性能的、基于内存的键值数据库,它支持多种数据结构,如字符串、列表、集合、散列、有序集合等。其中,Redis的散列(Hash)结构是一个常用的结构,今天跟大家分享一个我的日常操作,如何使用Redis的散列(Hash)结构来缓存和查询对象的属性值,以及如何用Lambda表达式树来简化这个过程.
Redis Hash结构是一种键值对的集合,它可以存储一个对象的多个字段和值。例如,我们可以用一个Hash结构来存储一个人的信息,如下所示:
HSET person: 1 id 1 HSET person: 1 name Alice HSET person: 1 age 20
上面的命令将一个人的信息存储到了一个名为person:1的Hash结构中,其中每个字段都有一个名称和一个值。我们可以使用HGET命令来获取某个字段的值,例如:
HGET person:
1
name#Alice
我们也可以使用HGETALL命令来获取所有字段的值,例如:
HGETALL person:1 id 1name Aliceage 20
为了在C#中操作Redis Hash结构,我们需要使用一个第三方库:StackExchange.Redis。这个库提供了一个ConnectionMultiplexer类,用于创建和管理与Redis服务器的连接,以及一个IDatabase接口,用于执行各种命令。例如,我们可以使用以下代码来创建一个连接对象和一个数据库对象:
// 连接Redis服务器 ConnectionMultiplexer redis = ConnectionMultiplexer.Connect( " localhost " ); // 获取数据库对象IDatabase db = redis.GetDatabase();
然后,我们可以使用db对象的HashSet方法和HashGet方法来存储和获取Hash结构中的字段值.
// 创建一个HashEntry数组,存放要缓存的对象属性 HashEntry[] hashfield = new HashEntry[ 3 ]; hashfield[ 0 ] = new HashEntry( " id " , " 1 " ); hashfield[ 1 ] = new HashEntry( " name " , " Alice " ); hashfield[ 2 ] = new HashEntry( " age " , " 20 " ); // 使用HashSet方法将对象属性缓存到Redis的散列(Hash)结构中 db.HashSet( " person:1 " , hashfield); // 使用HashGetAll方法从Redis的散列(Hash)结构中查询对象属性 HashEntry[] result = db.HashGetAll( " person:1 " ); // 遍历结果数组,打印对象属性 foreach ( var item in result) { Console.WriteLine(item.Name + " : " + item.Value); }
但是,这种方式有一些缺点:
有没有更优雅的方法来解决这个问题呢?答案是肯定的.
Lambda表达式是一种匿名函数,可以用来表示委托或表达式树。在.NET中,我们可以使用Lambda表达式来操作实体类的属性,比如获取属性的值或者更新属性的值.
我们可以利用 Lambda表达式来指定要存储或获取的对象的属性,而不是使用字符串。使用表达式树来遍历Lambda表达式,提取出属性名和属性值,并转换为HashEntry数组或RedisValue数组,使其更易于使用。例如:
Get<Person>(p =>
new
{ p.Name, p.Age });
如果我们只想选择一个属性,就可以直接写:
Get<Person>(p => p.Name)
如果要更新对象指定的属性,可以这样写了:
Update<Person>(p => p .SetProperty(x => x.Name, " Alice " ) .SetProperty(x => x.Age, 25 ));
怎么样,这样是不是优雅多了,这样做有以下好处:
那么,我们如何实现上面的方法呢?
这个方法的目的是从缓存中获取对象的一个或多个属性值,使用一个泛型方法和一个Lambda表达式来实现.
private static TResult Get<T, TResult>(IDatabase db, int id, Expression<Func<T, TResult>> selector) { if (selector == null ) throw new ArgumentNullException(nameof(selector)); // 使用扩展方法获取要查询的属性名数组 var hashFields = selector.GetMemberNames().Select(m => new RedisValue(m)).ToArray(); // 从缓存中获取对应的属性值数组 var values = db.HashGet($ " person:{id} " , hashFields); // 使用扩展方法将HashEntry数组转换为对象 var obj = values.ToObject<T> (hashFields); // 返回查询结果 return selector.Compile()(obj); } private static TResult Get<TResult>(IDatabase db, int id, Expression<Func<Person, TResult>> selector) => Get<Person, TResult>(db, id, selector);
这个类的作用是遍历一个表达式树,收集其中的成员表达式的名称,并存储到一个列表中.
public class MemberExpressionVisitor : ExpressionVisitor { private readonly IList< string > _names; public MemberExpressionVisitor(IList< string > list) { _names = list; } protected override Expression VisitMember(MemberExpression node) { var name = node.Member.Name; if (node.Expression is MemberExpression member) { Visit(member); name = member.Member.Name + " . " + name; } _names.Add(name); return base .VisitMember(node); } }
这个方法目的是将一个对象指定的属性名和值更新到缓存中,使用一个泛型方法和一个委托函数来实现.
public static Dictionary< string , object > Update<TSource>(Func<SetPropertyCalls<TSource>, SetPropertyCalls<TSource>> setPropertyCalls) { if (setPropertyCalls == null ) throw new ArgumentNullException(nameof(setPropertyCalls)); var nameValues = new Dictionary< string , object >( 100 ); // 创建一个字典用于存储属性名和值 var calls = new SetPropertyCalls<TSource>(nameValues); // 创建一个SetPropertyCalls对象 setPropertyCalls(calls); // 调用传入的函数,将属性名和值添加到字典中 return nameValues; // 返回字典 } private static void Update(IDatabase db, int id, Func<SetPropertyCalls<Person>, SetPropertyCalls<Person>> setPropertyCalls) { var hashEntries = Update(setPropertyCalls) .Select(kv => new HashEntry(kv.Key, kv.Value != null ? kv.Value.ToString() : RedisValue.EmptyString)) .ToArray(); // 将HashEntry数组存储到缓存中,使用对象的Id作为键 db.HashSet(id.ToString(), hashEntries); }}
这个类的作用是收集一个源对象的属性名称和值的对应关系,并提供一个链式调用的方法,用于设置属性的值.
public class SetPropertyCalls<TSource> { private readonly Dictionary< string , object > _nameValues; public SetPropertyCalls(Dictionary< string , object > nameValues) { _nameValues = nameValues; } public SetPropertyCalls<TSource> SetProperty<TProperty>(Expression<Func<TSource, TProperty>> propertyExpression, TProperty valueExpression) { if (propertyExpression == null ) throw new ArgumentNullException(nameof(propertyExpression)); if (propertyExpression.Body is MemberExpression member && member.Member is PropertyInfo property) { if (! _nameValues.TryAdd(property.Name, valueExpression)) { throw new ArgumentException($ " The property '{property.Name}' has already been set. " ); } } return this ; } }
这样,我们就可以得到一个包含所有要更新的属性名和值的字典,然后我们就可以根据这些属性名和值来更新实体类的属性了.
让我们来看一下代码示例,为了方便演示和阅读,这是临时码的,实际中大家可以根据自己习惯来进行封装,简化调用,同时也可以使用静态字典来缓存编译好的委托及对象属性,提高性能.
👇感谢阅读,点赞+分享+收藏+关注👇 。
公众号:猿惑豁 。
写作不易,转载请注明博文地址,否则禁转!!! 。
最后此篇关于如何使用C#中的Lambda表达式操作RedisHash结构,简化缓存中对象属性的读写操作的文章就讲到这里了,如果你想了解更多关于如何使用C#中的Lambda表达式操作RedisHash结构,简化缓存中对象属性的读写操作的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我阅读了有关 JSR 107 缓存 (JCache) 的内容。 我很困惑:据我所知,每个 CPU 都管理其缓存内存(无需操作系统的任何帮助)。 那么,为什么我们需要 Java 缓存处理程序? (如果C
好吧,我是 jQuery 的新手。我一直在这里和那里搞乱一点点并习惯它。我终于明白了(它并不像某些人想象的那么难)。因此,鉴于此链接:http://jqueryui.com/sortable/#dis
我正在使用 Struts 2 和 Hibernate。我有一个简单的表,其中包含一个日期字段,用于存储有关何时发生特定操作的信息。这个日期值显示在我的 jsp 中。 我遇到的问题是hibernate更
我有点不确定这里发生了什么,但是我试图解释正在发生的事情,也许一旦我弄清楚我到底在问什么,就可能写一个更好的问题。 我刚刚安装了Varnish,对于我的请求时间来说似乎很棒。这是一个Magneto 2
解决 Project Euler 的问题后,我在论坛中发现了以下 Haskell 代码: fillRow115 minLength = cache where cache = ((map fill
我正试图找到一种方法来为我网络上的每台计算机缓存或存储某些 python 包。我看过以下解决方案: pypicache但它不再被积极开发,作者推荐 devpi,请参见此处:https://bitbuc
我想到的一个问题是可以从一开始就缓存网络套接字吗?在我的拓扑中,我在通过双 ISP 连接连接到互联网的 HAProxy 服务器后面有 2 个 Apache 服务器(带有 Google PageSpee
我很难说出不同缓存区域 (OS) 之间的区别。我想简要解释一下磁盘\缓冲区\交换\页面缓存。他们住在哪里?它们之间的主要区别是什么? 据我了解,页面缓存是主内存的一部分,用于存储从 I/O 设备获取的
1.题目 请你为最不经常使用(LFU)缓存算法设计并实现数据结构。 实现 LFUCache 类: LFUCache(int capacity) - 用数据结构的容量 capacity 初始化对象 in
1.题目 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类: ① LRUCache(int capacity) 以正整数作为容量 capacity
我想在访问该 View 时关闭某些页面的缓存。它适用于简单查询模型对象的页面。 好像什么时候 'django.middleware.cache.FetchFromCacheMiddleware', 启
documents为 ExePackage element state Cache属性的目的是 Whether to cache the package. The default is "yes".
我知道 docker 用图层存储每个图像。如果我在一台开发服务器上有多个用户,并且每个人都在运行相同的 Dockerfile,但将镜像存储为 user1_myapp . user2 将其存储为 use
在 Codeigniter 中没有出现缓存问题几年后,我发现了一个问题。我在其他地方看到过该问题,但没有适合我的解决方案。 例如,如果我在 View 中更改一些纯 html 文本并上传新文件并按 F5
我在 Janusgraph 文档中阅读了有关 Janusgraph Cache 的内容。关于事务缓存,我几乎没有怀疑。我在我的应用程序中使用嵌入式 janusgrah 服务器。 如果我只对例如进行读取
我想知道是否有来自终端的任何命令可以用来匹配 Android Studio 中执行文件>使缓存无效/重新启动的使用。 谢谢! 最佳答案 According to a JetBrains employe
我想制作一个 python 装饰器来内存函数。例如,如果 @memoization_decorator def add(a, b, negative=False): print "Com
我经常在 jQuery 事件处理程序中使用 $(this) 并且从不缓存它。如果我愿意的话 var $this = $(this); 并且将使用变量而不是构造函数,我的代码会获得任何显着的额外性能吗?
是的,我要说实话,我不知道varnish vcl,我可以解决一些基本问题,但是我不太清楚,这就是为什么我遇到问题了。 我正在尝试通过http请求设置缓存禁止,但是该请求不能通过DNS而是通过 Varn
在 WP 站点上加载约 4000 个并发用户时遇到此问题。 这是我的配置: F5 负载均衡器 ---> Varnish 4,8 核,32 Gb RAM ---> 9 个后端,4 个核,每个 16 RA
我是一名优秀的程序员,十分优秀!