Skip to content

Commit

Permalink
Fixed yet another Include + Select() combo. Closes GH-3192
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremydmiller committed May 14, 2024
1 parent 49b962a commit 05e791d
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 7 deletions.
6 changes: 3 additions & 3 deletions docs/documents/querying/linq/include.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ public void multiple_includes()
reporter2.Id.ShouldBe(reporter.Id);
}
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/LinqTests/Includes/end_to_end_query_with_include.cs#L694-L725' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_multiple_include' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/LinqTests/Includes/end_to_end_query_with_include.cs#L730-L761' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_multiple_include' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

## Mapping to documents on any property
Expand Down Expand Up @@ -182,7 +182,7 @@ public void include_using_custom_map()
user2.ShouldNotBeNull();
}
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/LinqTests/Includes/end_to_end_query_with_include.cs#L899-L924' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_include_using_custom_map' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/LinqTests/Includes/end_to_end_query_with_include.cs#L935-L960' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_include_using_custom_map' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

By joining on a value other than the document id, this opens up the possibility of one-to-many joins, with potentially many related documents matching the queried document. Using a list as described above will allow for all matching records to be returned. Alternatively you can also use a dictionary of lists, where the key is the Id type and the value is an `IList` of a type corresponding to the Document type:
Expand Down Expand Up @@ -221,7 +221,7 @@ public void include_to_dictionary_list()
dict[class2.RoomCode].Count.ShouldBe(2);
}
```
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/LinqTests/Includes/end_to_end_query_with_include.cs#L926-L959' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_dictionary_list_include' title='Start of snippet'>anchor</a></sup>
<sup><a href='https://github.com/JasperFx/marten/blob/master/src/LinqTests/Includes/end_to_end_query_with_include.cs#L962-L995' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample_dictionary_list_include' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

## Asynchronous Support
Expand Down
36 changes: 36 additions & 0 deletions src/LinqTests/Includes/end_to_end_query_with_include.cs
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,42 @@ public void include_to_dictionary()

#endregion

[Fact]
public void include_to_dictionary_with_select()
{
var user1 = new User();
var user2 = new User();
var user3 = new User();

var issue1 = new Issue { AssigneeId = user1.Id, Title = "Garage Door is busted", Status = "Done", Number = 1};
var issue2 = new Issue { AssigneeId = user2.Id, Title = "Garage Door is busted", Status = "Done", Number = 2};
var issue3 = new Issue { AssigneeId = user2.Id, Title = "Garage Door is busted" };
var issue4 = new Issue { AssigneeId = user2.Id, Title = "Garage Door is busted" };
var issue5 = new Issue { AssigneeId = user3.Id, Title = "Garage Door is busted" };

using var session = theStore.IdentitySession();
session.Store(user1, user2);
session.Store(issue1, issue2, issue3);
session.SaveChanges();

using var query = theStore.QuerySession();
var dict = new Dictionary<Guid, User>();

query.Logger = new TestOutputMartenLogger(_output);

var ids = query.Query<Issue>().Include(dict).On(x => x.AssigneeId)
.Where(x => x.Status == "Done")
.Select(x => x.Number).ToArray();

dict.Count.ShouldBe(2);
dict.ContainsKey(user1.Id).ShouldBeTrue();
dict.ContainsKey(user2.Id).ShouldBeTrue();

ids.Length.ShouldBe(2);
ids.ShouldContain(1);
ids.ShouldContain(2);
}

[Fact]
public void include_to_dictionary_using_inner_join()
{
Expand Down
4 changes: 2 additions & 2 deletions src/Marten/Linq/SqlGeneration/NewScalarSelectClause.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

namespace Marten.Linq.SqlGeneration;

internal class NewScalarSelectClause<T>: ISelectClause, ISelector<T>, IScalarSelectClause, ISelector<T?>
internal class NewScalarSelectClause<T>: ISelectClause, ISelector<T>, IScalarSelectClause, ISelector<T?>, IModifyableFromObject
where T : struct
{
private static readonly string NullResultMessage =
Expand Down Expand Up @@ -51,7 +51,7 @@ public ISelectClause CloneToDouble()

public Type SelectedType => typeof(T);

public string FromObject { get; }
public string FromObject { get; set; }

public void Apply(ICommandBuilder sql)
{
Expand Down
4 changes: 2 additions & 2 deletions src/Marten/Linq/SqlGeneration/NewScalarStringSelectClause.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

namespace Marten.Linq.SqlGeneration;

internal class NewScalarStringSelectClause: ISelectClause, IScalarSelectClause, ISelector<string>
internal class NewScalarStringSelectClause: ISelectClause, IScalarSelectClause, ISelector<string>, IModifyableFromObject
{
public NewScalarStringSelectClause(string member, string from)
{
Expand Down Expand Up @@ -47,7 +47,7 @@ public ISelectClause CloneToDouble()

public Type SelectedType => typeof(string);

public string FromObject { get; }
public string FromObject { get; set; }

public void Apply(ICommandBuilder sql)
{
Expand Down

0 comments on commit 05e791d

Please sign in to comment.