diff --git a/src/Marten/Internal/CompiledQueries/QueryCompiler.cs b/src/Marten/Internal/CompiledQueries/QueryCompiler.cs index 9e574d908a..a02753977a 100644 --- a/src/Marten/Internal/CompiledQueries/QueryCompiler.cs +++ b/src/Marten/Internal/CompiledQueries/QueryCompiler.cs @@ -141,7 +141,7 @@ public static CompiledQueryPlan BuildQueryPlan(QuerySession session, var plan = new CompiledQueryPlan(query.GetType(), typeof(TOut)){TenantId = session.TenantId}; - assertValidityOfQueryType(plan, query.GetType()); + assertValidityOfQueryType(plan, query.GetType(), session.Options); // This *could* throw var queryTemplate = plan.CreateQueryTemplate(query); @@ -211,10 +211,21 @@ private static void eliminateStringNulls(object query) } - private static void assertValidityOfQueryType(CompiledQueryPlan plan, Type type) + private static void assertValidityOfQueryType(CompiledQueryPlan plan, Type type, StoreOptions options) { if (plan.InvalidMembers.Any()) { + // Remove any value types here! + foreach (var member in plan.InvalidMembers.Where(x => !x.GetRawMemberType().IsNullable()).ToArray()) + { + if (options.TryFindValueType(member.GetMemberType()) != null) + { + plan.InvalidMembers.Remove(member); + } + } + + if (!plan.InvalidMembers.Any()) return; + var members = plan.InvalidMembers.Select(x => $"{x.GetRawMemberType().NameInCode()} {x.Name}") .Join(", "); var message = $"Members {members} cannot be used as parameters to a compiled query"; diff --git a/src/ValueTypeTests/linq_querying_with_value_types.cs b/src/ValueTypeTests/linq_querying_with_value_types.cs index 16da824aaa..9ba590af30 100644 --- a/src/ValueTypeTests/linq_querying_with_value_types.cs +++ b/src/ValueTypeTests/linq_querying_with_value_types.cs @@ -1,7 +1,10 @@ using System; +using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; using System.Threading.Tasks; using Marten; +using Marten.Linq; using Marten.Testing.Harness; using Vogen; @@ -69,6 +72,34 @@ public async Task store_several_and_query_by() ordered.ShouldHaveTheSameElementsAs(doc4.Id); } + + [Fact] + public async Task use_value_type_as_parameter_in_compiled_query() + { + var doc1 = new LimitedDoc { Lower = LowerLimit.From(1), Upper = UpperLimit.From(20) }; + var doc2 = new LimitedDoc { Lower = LowerLimit.From(5), Upper = UpperLimit.From(25) }; + var doc3 = new LimitedDoc { Lower = LowerLimit.From(4), Upper = UpperLimit.From(15) }; + var doc4 = new LimitedDoc { Lower = LowerLimit.From(3), Upper = UpperLimit.From(10) }; + + theSession.Store(doc1, doc2, doc3, doc4); + await theSession.SaveChangesAsync(); + + var raw = await theSession.QueryAsync(new LimitedDocQuery()); + var ordered = raw.Select(x => x.Id).ToArray(); + + ordered.ShouldHaveTheSameElementsAs(doc4.Id); + } +} + +public class LimitedDocQuery: ICompiledListQuery +{ + public Expression, IEnumerable>> QueryIs() + { + return query => query.OrderBy(x => x.Lower) + .Where(x => x.Upper == Upper); + } + + public UpperLimit Upper { get; set; } = UpperLimit.From(10); } #region sample_limited_doc