Skip to content

Commit 9cdce7b

Browse files
committed
Publish: Querylink concept
1 parent 9b757e6 commit 9cdce7b

File tree

8 files changed

+183
-217
lines changed

8 files changed

+183
-217
lines changed

content/blog/2025/20250121_ulid-announcement/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: "Announcing ByteAether.Ulid v1.0.0: A High-Performance .NET ULID Library for Modern Applications"
33
date: 2025-01-21
44
image: header.png
5-
tags: ["ulid", "uuid", "guid", "unique identifier", "id"]
5+
tags: ["ulid", "uuid", "guid", "id"]
66
---
77

88
Frustrated with GUIDs that aren’t sortable or human-readable? Meet ByteAether.Ulid - a ULID library designed to simplify your .NET development.

content/blog/2025/20250128_ulid-intro/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: "An Introduction to ULIDs: A Modern Identifier for Software Systems"
33
date: 2025-01-28
4-
tags: ["uuid", "ulid", "guid", "unique identifier", "id"]
4+
tags: ["uuid", "ulid", "guid", "id"]
55
image: header.png
66
---
77
In the world of software development, identifiers are a cornerstone of data storage and retrieval. Whether you are designing a database, an API, or a distributed system, choosing the right identifier scheme is critical to ensuring performance, scalability, and reliability. Two widely used options are auto-incrementing integers and UUIDs (Universally Unique Identifiers). While each has its strengths, they also come with significant trade-offs. ULIDs (Universally Unique Lexicographically Sortable Identifiers) have emerged as a modern alternative that combines the best of both worlds. This article introduces ULIDs by first exploring the strengths and limitations of traditional identifier schemes and then delving into the advantages of ULIDs.
1.35 MB
Loading
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
---
2+
title: "Seamlessly Connecting Frontend and Backend Data in .NET Applications: A New Paradigm for Effortless Integration"
3+
date: 2025-02-18
4+
tags: ["querylink", "integration", "entity-framework", "linq", "sql", "fullstack", "database"]
5+
image: header.png
6+
---
7+
In today's fast‐paced software development world, engineers are often forced to write repetitive integration logic to connect user interfaces - especially data grids and tables - to their backend data sources. Every project, every new feature, and every iteration seems to reintroduce the same challenges: how do we reliably filter, sort, and display data without reinventing the wheel each time? The answer lies in automating these common tasks, thereby freeing developers to focus on business logic rather than boilerplate code.
8+
9+
## The Problem: Repetitive Integration Logic
10+
11+
Consider a typical .NET application where you need to fetch, filter, and sort data from a SQL database using Entity Framework Core. In many projects, developers are repeatedly writing similar code snippets to achieve this functionality. For example:
12+
13+
```csharp
14+
// Example: Manually applying filters and sorting on a data source
15+
public IQueryable<Person> GetFilteredAndSortedPeople(
16+
ApplicationDbContext dbContext,
17+
string name,
18+
int? minAge,
19+
string sortField
20+
)
21+
{
22+
IQueryable<Person> query = dbContext.People.AsQueryable();
23+
24+
// Repetitive filtering logic:
25+
if (!string.IsNullOrWhiteSpace(name))
26+
{
27+
query = query.Where(p => p.Name == name);
28+
}
29+
if (minAge.HasValue)
30+
{
31+
query = query.Where(p => p.Age >= minAge.Value);
32+
}
33+
34+
// Repetitive sorting logic:
35+
if (sortField == "Name")
36+
{
37+
query = query.OrderBy(p => p.Name);
38+
}
39+
else if (sortField == "Age")
40+
{
41+
query = query.OrderByDescending(p => p.Age);
42+
}
43+
44+
return query;
45+
}
46+
```
47+
48+
Now, imagine this pattern repeated across multiple controllers, services, and even projects. Each time you need to tweak a filter or adjust a sort order, you are forced to manually update these code blocks - often duplicating logic and introducing room for inconsistencies or bugs.
49+
50+
Another example might involve converting query parameters from the UI into LINQ expressions:
51+
52+
```csharp
53+
// Example: Converting UI query parameters into LINQ filter expressions
54+
public IQueryable<Product> FilterProducts(
55+
IQueryable<Product> query,
56+
Dictionary<string, string> filters
57+
)
58+
{
59+
foreach (var filter in filters)
60+
{
61+
switch (filter.Key.ToLower())
62+
{
63+
case "category":
64+
query = query.Where(p => p.Category == filter.Value);
65+
break;
66+
case "price":
67+
if (decimal.TryParse(filter.Value, out var price))
68+
{
69+
query = query.Where(p => p.Price >= price);
70+
}
71+
break;
72+
default:
73+
break;
74+
}
75+
}
76+
77+
return query;
78+
}
79+
```
80+
81+
### Problems with this approach:
82+
- **Wastes valuable time**: Developers must repeatedly implement similar logic across different parts of an application.
83+
- **Increases error potential**: Manual adjustments lead to inconsistencies and bugs.
84+
- **Reduces maintainability**: Updates must be applied in multiple places, making maintenance a challenge.
85+
86+
Clearly, there is a need for a generic, reusable solution that abstracts away this repetitive integration logic.
87+
88+
## Identifying the Requirements for a Generic Solution
89+
90+
To create a generic solution for handling data integration, certain core requirements must be met:
91+
92+
### 1. Serializability
93+
For a solution to work seamlessly between the client and server, its filter and order definitions must be serializable. This allows easy transmission over HTTP without losing state.
94+
95+
### 2. Integration with IQueryable and EF Core
96+
The solution must work directly with `IQueryable`, ensuring that filtering and sorting logic is applied at the database level, improving performance.
97+
98+
### 3. Flexible Filter Definitions
99+
A robust solution should support a variety of filtering operators such as:
100+
- **Equals (`=`) / Not Equals (`!=`)**
101+
- **Greater Than (`>`) / Less Than (`<`)**
102+
- **Contains (`=*`)**
103+
104+
... and more.
105+
106+
### 4. Support for Overrides
107+
Developers should be able to specify overrides for sorting and filtering logic to handle cases where default behavior isn't sufficient. For example, sorting should support custom overrides, like sorting `Firstname` as `[Firstname] [Lastname]` to ensure consistent ordering.
108+
109+
## A Modern Approach to Automating Data Query Integration
110+
111+
An innovative solution was born: **[QueryLink](https://github.com/ByteAether/QueryLink/)**. This library encapsulates all the above requirements into a single, easy-to-use package.
112+
113+
**Key Features:**
114+
1. **Filter and Order Definitions**: Define filters and sorting orders without writing complex LINQ expressions.
115+
2. **Expression-based Overrides**: Customize filtering or sorting logic using lambda expressions with type safety.
116+
3. **Query String Conversion**: Convert definitions to query strings for seamless transmission over `GET` parameters.
117+
4. **Direct IQueryable Integration**: Ensures efficient query execution at the database level.
118+
119+
## Getting Started: Hands-On Code Examples
120+
121+
### Defining Filters and Sorting Orders
122+
123+
```csharp
124+
var definitions = new Definitions
125+
{
126+
Filters =
127+
[
128+
new("Name", FilterOperator.Eq, "John"),
129+
new("Age", FilterOperator.Gt, 30)
130+
],
131+
Orders =
132+
[
133+
new("Name"),
134+
new("Age", IsReversed: true)
135+
]
136+
};
137+
```
138+
139+
### Customizing with Overrides (Optional)
140+
141+
```csharp
142+
var overrides = new Overrides<Person>
143+
{
144+
Filter =
145+
[
146+
new(p => p.Name, p => p.FullName)
147+
],
148+
Order =
149+
[
150+
new(p => p.Name, p => p.FullName)
151+
]
152+
};
153+
```
154+
155+
### Applying Definitions to an IQueryable Source
156+
157+
```csharp
158+
IQueryable<Person> query = dbContext.People.AsQueryable();
159+
query = query.Apply(definitions, overrides);
160+
```
161+
162+
## Embracing the New Way of Integration Logic
163+
164+
With QueryLink:
165+
- **Eliminate Repetitiveness**: No more writing the same boilerplate code repeatedly.
166+
- **Improve Code Clarity**: Declarative definitions make code easier to read and maintain.
167+
- **Enhance Consistency**: Apply the same filtering and sorting logic across the application.
168+
- **Speed Up Development**: Focus on business logic instead of integration logic.
169+
170+
## Why QueryLink Is a Must-Have in Every .NET Project
171+
172+
QueryLink transforms UI-to-database integration by:
173+
- **Streamlining Development**: Reducing the need for repetitive query logic.
174+
- **Ensuring Consistency**: Standardizing filtering and sorting mechanisms.
175+
- **Enhancing Maintainability**: Centralizing data integration logic.
176+
177+
Given these advantages, **QueryLink is an essential library for every full-stack .NET application**. By integrating this tool into your workflow, you empower your team to build more efficient and maintainable software.
178+
179+
*Embrace the future of data integration with QueryLink.*
180+
181+
[Check out the QueryLink repository on GitHub](https://github.com/ByteAether/QueryLink/).

content/blog/2025/_choosing-uuid-ulid/index.md

Lines changed: 0 additions & 64 deletions
This file was deleted.
-330 KB
Binary file not shown.

0 commit comments

Comments
 (0)