Supported Linq Operators
Element Operations
Marten has been successfully tested with these element operations:
First()
FirstAsync()
-- Marten specificSingle()
SingleAsync()
-- Marten specificFirstOrDefault()
FirstOrDefaultAsync()
-- Marten specificSingleOrDefault()
SingleOrDefaultAsync()
-- Marten specific
public void select_a_single_value(IDocumentSession session)
{
// Single()/SingleOrDefault() will throw exceptions if more than
// one result is returned from the database
session.Query<Target>().Where(x => x.Number == 5).Single();
session.Query<Target>().Where(x => x.Number == 5).SingleOrDefault();
session.Query<Target>().Where(x => x.Number == 5).OrderBy(x => x.Date).First();
session.Query<Target>().Where(x => x.Number == 5).OrderBy(x => x.Date).FirstOrDefault();
session.Query<Target>().Where(x => x.Number == 5).OrderBy(x => x.Date).Last();
session.Query<Target>().Where(x => x.Number == 5).OrderBy(x => x.Date).LastOrDefault();
// Using the query inside of Single/Last/First is supported as well
session.Query<Target>().Single(x => x.Number == 5);
}
Filtering Documents
Since you usually don't want to pull down the entire database at one time, Marten supports these basic operators in Linq searches:
public async Task basic_operators(IDocumentSession session)
{
// Field equals a value
await session.Query<Target>().Where(x => x.Number == 5).ToListAsync();
// Field does not equal a value
await session.Query<Target>().Where(x => x.Number != 5).ToListAsync();
// Field compared to values
await session.Query<Target>().Where(x => x.Number > 5).ToListAsync();
await session.Query<Target>().Where(x => x.Number >= 5).ToListAsync();
await session.Query<Target>().Where(x => x.Number < 5).ToListAsync();
await session.Query<Target>().Where(x => x.Number <= 5).ToListAsync();
}
Marten's Linq support will also allow you to make "deep" searches on properties of properties (or fields):
public void deep_queries(IDocumentSession session)
{
session.Query<Target>().Where(x => x.Inner.Number == 3);
}
Right now, Marten supports both and and or queries with Linq:
public void and_or(IDocumentSession session)
{
// AND queries
session.Query<Target>().Where(x => x.Number > 0 && x.Number <= 5);
// OR queries
session.Query<Target>().Where(x => x.Number == 5 || x.Date == DateTime.Today);
}
Ordering Results
Marten contains support for expressing ordering in both ascending and descending order in Linq queries:
public void order_by(IDocumentSession session)
{
// Sort in ascending order
session.Query<Target>().OrderBy(x => x.Date);
// Sort in descending order
session.Query<Target>().OrderByDescending(x => x.Date);
// You can use multiple order by's
session.Query<Target>().OrderBy(x => x.Date).ThenBy(x => x.Number);
}
Aggregate Functions
::: In many cases the asynchronous versions of these operators are extension methods within Marten itself as these were not present in core IQueryable
at the time Marten's Linq support was developed. :::
Marten has been successfully tested with these aggregation operators:
Count()
/CountAsync()
LongCount()
/LongCountAsync()
Min()
/MinAsync()
Max()
/MaxAsync()
Sum()
/SumAsync()
Average()
/AverageAsync()
public async Task sample_aggregation_operations(IQuerySession session)
{
var count = session.Query<Target>().Count();
var count2 = await session.Query<Target>().CountAsync();
var count3 = session.Query<Target>().LongCount();
var count4 = await session.Query<Target>().LongCountAsync();
var min = await session.Query<Target>().MinAsync(x => x.Number);
var max = await session.Query<Target>().MaxAsync(x => x.Number);
var sum = await session.Query<Target>().SumAsync(x => x.Number);
var average = await session.Query<Target>().AverageAsync(x => x.Number);
}
Partitioning Operators
Marten has been successfully tested with these partition operators:
Take()
Skip()
public void using_take_and_skip(IDocumentSession session)
{
// gets records 11-20 from the database
session.Query<Target>().Skip(10).Take(10).OrderBy(x => x.Number).ToArray();
}
TODO -- link to the paging support
Grouping Operators
Sorry, but Marten does not yet support GroupBy()
. You can track this GitHub issue to follow any future work on this Linq operator.
Distinct()
New in Marten 1.2 is support for the Linq Distinct()
operator:
[Fact]
public void get_distinct_string()
{
theSession.Store(new Target {String = "one"});
theSession.Store(new Target {String = "one"});
theSession.Store(new Target {String = "two"});
theSession.Store(new Target {String = "two"});
theSession.Store(new Target {String = "three"});
theSession.Store(new Target {String = "three"});
theSession.SaveChanges();
var queryable = theSession.Query<Target>().Select(x => x.String).Distinct();
queryable.ToList().Count.ShouldBe(3);
}
Do note that the Distinct()
keyword can be used with Select()
transforms as well:
[SerializerTypeTargetedFact(RunFor = SerializerType.Newtonsoft)]
public void get_distinct_numbers()
{
theSession.Store(new Target {Number = 1, Decimal = 1.0M});
theSession.Store(new Target {Number = 1, Decimal = 2.0M});
theSession.Store(new Target {Number = 1, Decimal = 2.0M});
theSession.Store(new Target {Number = 2, Decimal = 1.0M});
theSession.Store(new Target {Number = 2, Decimal = 2.0M});
theSession.Store(new Target {Number = 2, Decimal = 1.0M});
theSession.SaveChanges();
var queryable = theSession.Query<Target>().Select(x => new
{
x.Number,
x.Decimal
}).Distinct();
queryable.ToList().Count.ShouldBe(4);
}
Modulo Queries
Marten has the ability to use the modulo operator in Linq queries:
[Fact]
public void use_modulo()
{
theSession.Store(new Target{Color = Colors.Blue, Number = 1});
theSession.Store(new Target{Color = Colors.Blue, Number = 2});
theSession.Store(new Target{Color = Colors.Blue, Number = 3});
theSession.Store(new Target{Color = Colors.Blue, Number = 4});
theSession.Store(new Target{Color = Colors.Blue, Number = 5});
theSession.Store(new Target{Color = Colors.Green, Number = 6});
theSession.SaveChanges();
theSession.Query<Target>().Where(x => x.Number % 2 == 0 && x.Color < Colors.Green).ToArray()
.Select(x => x.Number)
.ShouldHaveTheSameElementsAs(2, 4);
}