As I continued work on BrainExpanded and its MCP service, I came to realize that I needed support for dynamic entities and full text search in the Graph Model API. I just published a new release of the Cvoya Graph Model packages with many changes. Here’s a summary:
- Dynamic Entities. It’s no longer required to use strong types to interact with the graph model. The
DynamicNodeandDynamicRelationshiptypes provide the necessary support. - Full text search. It’s not possible to search the graph using full text search. The
PropertyAttributehas been updated to support options related to full text search (e.g.IncludeInFullTextSearch) or to schema-related requirements (e.g.IsRequired,IsUnique). - One package dependency. You can now get started easily by just adding the
Cvoya.Graph.Model.Neo4jpackage to your project. The necessary package dependencies will be included and the code generator will be automatically activated at build time of your project. TheCvoya.Graph.Model.Analyzerspackage is still optional but recommended. - All the examples now work. The code for some of the example projects on github was commented out for the last release. They all build and run to completion now. There is an example project for full-text search as well.
Example – Dynamic Entities
You can now use DynamicNode and DynamicRelationship for nodes and relationships:
// Create a node
var node = new DynamicNode(
labels: new[] { "Person" },
properties: new Dictionary<string, object?>
{
["name"] = "John Doe",
["age"] = 40,
["email"] = "john@example.com",
["active"] = true
}
);
await Graph.CreateNodeAsync(node);
It’s similar for relationships.
You can configure the properties using the introduced PropertyConfiguration-related API. Refer to the source code on github for more details. When I get some time, I will write an example and update the documentation.
Of course, it is possible to interact with the created node using a strong type:
public record Person : Node
{
[Property(Label = "name")]
public string FullName { get; set; }
[Property(Label = "age")]
public int Age { get; set; }
[Property(Label = "email")]
public string Email { get; set; }
[Property(Label = "active")]
public bool IsActive { get; set; }
}
var person = await graph.Nodes<Person>()
.Where(p => p.Id = "...")
.FirstOrDefaultAsync();
Example – Full Text Search
Every entity (node or relationship) with a string property is automatically added to the text index unless otherwise configured. There is a text index per property and a global one. You can search the global index using Search(), node/relationship indexes using SearchNodes() and SearchRelationships, or type-specific indexes using SearchNodes<Person>() and SearchRelationships<FriendsWith>(). You can then compose the search operators with other LINQ queries:
var johnsOver30 = await graph
.SearchNode<Person>("John")
.Where(p => p.Age > 30)
.ToListAsync()
Example – Get started
And now, it’s much easier to get started:
> dotnet new console
> dotnet add package Cvoya.Graph.Model.Neo4j -v 1.0.0-alpha.20250716.4
# optionally but recommended
> dotnet add package Cvoya.Graph.Model.Analyzers -v 1.0.0-alpha.20250716.4
Happy coding!