使用Neo4j Bolt .Net Driver实现查询结果转Movie对象及Cypher Merge转换
嘿,我来帮你搞定这两个需求!刚好我之前在WPF项目里用Neo4j做过类似的功能,给你分享下具体的实现思路和代码~
一、把Cypher查询结果转换为Movie对象列表
首先你得有一个和Neo4j Movie节点属性对应的C#实体类,比如:
public class Movie { public string Title { get; set; } public int ReleaseYear { get; set; } public string Tagline { get; set; } // 这里根据你Neo4j里Movie节点的实际属性补充,比如导演、演员关联之类的(如果需要的话) }
接下来处理查询结果:session.Run()返回的是IStatementResult,每个记录里的m是Neo4j的节点对象,我们可以把它转成INode,然后手动映射属性到Movie实例。代码如下:
using Neo4j.Driver.V1; using System.Collections.Generic; // 假设你已经通过GraphDatabase.Driver创建了driver,并且打开了session var result = session.Run("MATCH (m:Movie) RETURN m"); var movieList = new List<Movie>(); foreach (var record in result) { // 从记录中提取Movie节点 var movieNode = record["m"].As<INode>(); // 映射节点属性到Movie对象(注意处理属性不存在的情况) var movie = new Movie { Title = movieNode.Properties.TryGetValue("title", out var titleVal) ? titleVal.As<string>() : null, ReleaseYear = movieNode.Properties.TryGetValue("releaseYear", out var yearVal) ? yearVal.As<int>() : 0, Tagline = movieNode.Properties.TryGetValue("tagline", out var taglineVal) ? taglineVal.As<string>() : null // 其他属性照着这个格式加就行 }; movieList.Add(movie); }
这里用TryGetValue是为了避免某个属性在Neo4j节点中不存在时抛出异常,As<T>()是Neo4j Driver提供的类型转换方法,能把节点属性值转成对应的C#类型。
二、将C# Movie对象转换为Cypher Merge语句
Merge语句的好处是:如果节点存在就更新属性,不存在就创建新节点。我们可以写一个方法,根据Movie对象的属性动态生成安全的Merge语句,还要注意转义单引号防止语法错误。
方法1:手动生成字符串(适合简单场景)
public string GenerateMovieMergeQuery(Movie movie) { var propertyPairs = new List<string>(); // 过滤空值属性,避免更新或创建时写入无效值 if (!string.IsNullOrEmpty(movie.Title)) { // 转义单引号,防止Cypher语法错误 var escapedTitle = movie.Title.Replace("'", "\\'"); propertyPairs.Add($"title: '{escapedTitle}'"); } if (movie.ReleaseYear > 0) // 假设年份是有效的正数 { propertyPairs.Add($"releaseYear: {movie.ReleaseYear}"); } if (!string.IsNullOrEmpty(movie.Tagline)) { var escapedTagline = movie.Tagline.Replace("'", "\\'"); propertyPairs.Add($"tagline: '{escapedTagline}'"); } var propertiesStr = string.Join(", ", propertyPairs); // 这里用Title作为唯一匹配键,你可以根据业务改成其他唯一标识(比如ID) return $"MERGE (m:Movie {{title: '{movie.Title.Replace("'", "\\'")}'}}) " + $"SET m += {{{propertiesStr}}} " + $"RETURN m"; }
方法2:参数化查询(更安全、推荐)
如果Movie属性很多,或者担心注入风险,最好用参数化查询,Neo4j Driver支持直接传参数:
using Neo4j.Driver.V1; using System.Collections.Generic; using System.Threading.Tasks; public async Task MergeMovieAsync(ISession session, Movie movie) { // 构建参数字典,只包含非空属性 var props = new Dictionary<string, object>(); if (!string.IsNullOrEmpty(movie.Title)) props["title"] = movie.Title; if (movie.ReleaseYear > 0) props["releaseYear"] = movie.ReleaseYear; if (!string.IsNullOrEmpty(movie.Tagline)) props["tagline"] = movie.Tagline; // 参数化的Cypher语句,$开头的是参数占位符 var cypherQuery = @" MERGE (m:Movie {title: $title}) SET m += $properties RETURN m"; // 执行查询,传入参数 await session.RunAsync(cypherQuery, new { title = movie.Title, properties = props }); }
参数化查询不仅能避免语法错误,还能让Neo4j缓存查询计划,提升性能,同时彻底杜绝注入风险,非常推荐在生产环境使用。
内容的提问来源于stack exchange,提问作者Nerdherder Ed
相关产品推荐
相关产品推荐

