-
Notifications
You must be signed in to change notification settings - Fork 12
DocumentSession Query
github-actions[bot] edited this page Dec 16, 2025
·
3 revisions
HybridDb provides powerful querying capabilities through LINQ and SQL. You can query documents using projected columns for efficient database queries while still working with full document objects.
using var session = store.OpenSession();
var products = session.Query<Product>()
.Where(x => x.Price > 100)
.ToList();using var session = store.OpenSession();
var allProducts = session.Query<Product>().ToList();using var session = store.OpenSession();
var product = session.Query<Product>()
.Where(x => x.Name == "Widget")
.SingleOrDefault();using var session = store.OpenSession();
var product = session.Query<Product>()
.Where(x => x.Price > 50)
.FirstOrDefault();var session = store.OpenSession();
var products = session.Query<Product>()
.Where(x => x.CategoryId == "electronics")
.ToList();// Greater than
var expensive = session.Query<Product>()
.Where(x => x.Price > 1000)
.ToList();
// Less than or equal
var affordable = session.Query<Product>()
.Where(x => x.Price <= 50)
.ToList();// Is null
var noCategory = session.Query<Product>()
.Where(x => x.CategoryId == null)
.ToList();
// Is not null
var hasCategory = session.Query<Product>()
.Where(x => x.CategoryId != null)
.ToList();
### Logical Operators
<!-- snippet: LogicalOperators -->
<a id='snippet-LogicalOperators'></a>
```cs
// AND
var filtered = session.Query<Product>()
.Where(x => x.Price > 100 && x.CategoryId == "electronics")
.ToList();
// OR
var multiple = session.Query<Product>()
.Where(x => x.CategoryId == "electronics" || x.CategoryId == "computers")
.ToList();var products = session.Query<Product>()
.Where(x => x.Price > 50)
.Where(x => x.CategoryId == "electronics")
.Where(x => x.Stock > 0)
.ToList();// StartsWith
var startsWithPro = session.Query<Product>()
.Where(x => x.Name.StartsWith("Pro"))
.ToList();
// Contains
var containsWidget = session.Query<Product>()
.Where(x => x.Name.Contains("Widget"))
.ToList();
// EndsWith
var endsWith2000 = session.Query<Product>()
.Where(x => x.Name.EndsWith("2000"))
.ToList();var minPrice = 100m;
var category = "electronics";
var products = session.Query<Product>()
.Where(x => x.Price > minPrice && x.CategoryId == category)
.ToList();var filter = new { MinPrice = 100m, Category = "electronics" };
var products = session.Query<Product>()
.Where(x => x.Price > filter.MinPrice)
.ToList();// Order by ascending
var byPrice = session.Query<Product>()
.OrderBy(x => x.Price)
.ToList();
// Order by descending
var byPriceDesc = session.Query<Product>()
.OrderByDescending(x => x.Price)
.ToList();
// Multiple orderings
var multiOrder = session.Query<Product>()
.OrderBy(x => x.CategoryId)
.ThenByDescending(x => x.Price)
.ToList();// Take first 10
var firstPage = session.Query<Product>()
.OrderBy(x => x.Name)
.Take(10)
.ToList();
// Skip and take (pagination)
var secondPage = session.Query<Product>()
.OrderBy(x => x.Name)
.Skip(10)
.Take(10)
.ToList();// Count all
var totalCount = session.Query<Product>().Count();
// Count with filter
var expensiveCount = session.Query<Product>()
.Where(x => x.Price > 100)
.Count();
// Any
var hasProducts = session.Query<Product>().Any();
// Any with filter
var hasExpensive = session.Query<Product>()
.Where(x => x.Price > 1000)
.Any();var productSummaries = session.Query<Product>()
.Select(x => new
{
x.Id,
x.Name,
x.Price
})
.ToList();public class ProductSummary
{
public string Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
var summaries = session.Query<Product>()
.Select(x => new ProductSummary
{
Id = x.Id,
Name = x.Name,
Price = x.Price
})
.ToList();public abstract class Animal
{
public string Id { get; set; }
public string Name { get; set; }
}
public class Dog : Animal
{
public string Breed { get; set; }
}
public class Cat : Animal
{
public int Lives { get; set; }
}
// Query all animals
var allAnimals = session.Query<Animal>().ToList();// Query only dogs
var dogs = session.Query<Dog>().ToList();
// Filter by type
var bigDogs = session.Query<Animal>()
.OfType<Dog>()
.Where(d => d.Breed == "Great Dane")
.ToList();using var session = store.OpenSession();
var sql = new SqlBuilder()
.Append("SELECT * FROM Products")
.Append("WHERE Price > @minPrice", new SqlParameter("minPrice", 100));
var products = session.Query<Product>(sql).ToList();var sql = new SqlBuilder()
.Append("SELECT * FROM Products")
.Append("WHERE CategoryId = @category", new SqlParameter("category", "electronics"))
.Append("AND Price BETWEEN @minPrice AND @maxPrice",
new SqlParameter("minPrice", 100),
new SqlParameter("maxPrice", 1000));
var products = session.Query<Product>(sql).ToList();var sql = new SqlBuilder()
.Append("SELECT p.* FROM Products p")
.Append("INNER JOIN Categories c ON p.CategoryId = c.Id")
.Append("WHERE c.Name = @categoryName", new SqlParameter("categoryName", "Electronics"));
var products = session.Query<Product>(sql).ToList();var sql = new SqlBuilder(
parameters: new SqlParameter("status", "Active"),
new SqlParameter("minStock", 10))
.Append("SELECT * FROM Products")
.Append("WHERE Status = @status AND Stock >= @minStock");
var products = session.Query<Product>(sql).ToList();HybridDb uses projected columns for efficient querying:
// Configuration
store.Configuration.Document<Product>()
.With(x => x.Name)
.With(x => x.Price)
.With(x => x.CategoryId);
// Query uses projected columns
var products = session.Query<Product>()
.Where(x => x.Price > 100 && x.CategoryId == "electronics")
.ToList();
// Generated SQL uses columns:
// SELECT * FROM Products
// WHERE Price > 100 AND CategoryId = 'electronics'Query using column projections directly:
var products = session.Query<Product>()
.Where(x => x.Column<decimal>("Price") > 100)
.ToList();var categories = new[] { "electronics", "computers", "phones" };
var products = session.Query<Product>()
.Where(x => x.Column<string>("CategoryId").In(categories))
.ToList();// Fast: Uses projected column
var products = session.Query<Product>()
.Where(x => x.CategoryId == "electronics") // CategoryId is projected
.ToList();
// Slow: Scans document JSON
var products = session.Query<Product>()
.Where(x => x.SomeUnindexedProperty == "value") // Not indexed
.ToList();// Statistics are available through advanced API
var query = session.Query<Product>()
.Where(x => x.Price > 100);
// Execute and get stats
var products = query.ToList();public List<Product> SearchProducts(string searchTerm, string category, decimal? minPrice, decimal? maxPrice)
{
using var session = store.OpenSession();
var query = session.Query<Product>();
if (!string.IsNullOrEmpty(searchTerm))
{
query = query.Where(x => x.Name.Contains(searchTerm));
}
if (!string.IsNullOrEmpty(category))
{
query = query.Where(x => x.CategoryId == category);
}
if (minPrice.HasValue)
{
query = query.Where(x => x.Price >= minPrice.Value);
}
if (maxPrice.HasValue)
{
query = query.Where(x => x.Price <= maxPrice.Value);
}
return query.OrderBy(x => x.Name).ToList();public class PagedResult<T>
{
public List<T> Items { get; set; }
public int TotalCount { get; set; }
public int PageNumber { get; set; }
public int PageSize { get; set; }
public int TotalPages => (int)Math.Ceiling(TotalCount / (double)PageSize);
}
public PagedResult<Product> GetProductsPage(int pageNumber, int pageSize)
{
using (var session = store.OpenSession())
{
var query = session.Query<Product>()
.Where(x => x.Status == "Active");
var total = query.Count();
var items = query
.OrderBy(x => x.Name)
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize)
.ToList();
return new PagedResult<Product>
{
Items = items,
TotalCount = total,
PageNumber = pageNumber,
PageSize = pageSize
};
}public bool ProductExists(string productId)
{
using (var session = store.OpenSession())
{
return session.Advanced.Exists<Product>(productId, out _);
}
}
public bool HasProductsInCategory(string categoryId)
{
using (var session = store.OpenSession())
{
return session.Query<Product>()
.Any(x => x.CategoryId == categoryId);
}// Configure projections for properties you query
store.Configuration.Document<Product>()
.With(x => x.CategoryId) // Queried frequently
.With(x => x.Price) // Queried frequently
.With(x => x.Status); // Queried frequently// Good: Specific query
var product = session.Query<Product>()
.Where(x => x.Id == productId)
.FirstOrDefault();
// Better: Use Load for single document
var product = session.Load<Product>(productId);// Good: Use Take to limit results
var recentProducts = session.Query<Product>()
.OrderByDescending(x => x.CreatedDate)
.Take(10)
.ToList();
// Avoid: Loading all documents
var allProducts = session.Query<Product>().ToList(); // Could be huge!public List<Product> GetProducts()
{
using (var session = store.OpenSession())
{
// Documents won't be tracked or modified
return session.Query<Product>()
.Where(x => x.Status == "Active")
.ToList();
}// Good: Single query with multiple filters
var products = session.Query<Product>()
.Where(x => x.CategoryId == "electronics" && x.Price > 100 && x.Stock > 0)
.ToList();
// Avoid: Multiple database calls
var products = session.Query<Product>()
.Where(x => x.CategoryId == "electronics")
.ToList()
.Where(x => x.Price > 100) // In-memory filter
.ToList();Check that:
- Properties are indexed/projected
- Values match exactly (case-sensitive for strings)
- Documents exist in the table
- No soft-delete filtering
Optimize by:
- Adding database indexes on projected columns
- Reducing result set with filters
- Using specific queries instead of loading all
- Checking query execution plan
// Error: Property not indexed
var products = session.Query<Product>()
.Where(x => x.UnindexedProperty == "value") // Error!
.ToList();
// Fix: Add projection
store.Configuration.Document<Product>()
.With(x => x.UnindexedProperty);// Use appropriate types in queries
var products = session.Query<Product>()
.Where(x => x.Price > 100m) // Use decimal for decimal properties
.ToList();