Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP - Improve select clause transformation for Linq provider #2079

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
3 changes: 2 additions & 1 deletion src/NHibernate.DomainModel/Northwind/Entities/Animal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ public class Animal
public virtual Animal Father { get; set; }
public virtual IList<Animal> Children { get; set; }
public virtual string SerialNumber { get; set; }

public virtual string FatherSerialNumber => Father?.SerialNumber;
public virtual bool HasFather => Father != null;
public virtual Animal FatherOrMother => Father ?? Mother;
}

Expand Down
18 changes: 18 additions & 0 deletions src/NHibernate.DomainModel/Northwind/Entities/DynamicUser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Collections;

namespace NHibernate.DomainModel.Northwind.Entities
{
public class DynamicUser : IEnumerable
{
public virtual int Id { get; set; }

public virtual dynamic Properties { get; set; }

public virtual IDictionary Settings { get; set; }

public virtual IEnumerator GetEnumerator()
{
throw new System.NotImplementedException();
}
}
}
5 changes: 5 additions & 0 deletions src/NHibernate.DomainModel/Northwind/Entities/Northwind.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ public IQueryable<User> Users
get { return _session.Query<User>(); }
}

public IQueryable<DynamicUser> DynamicUsers
{
get { return _session.Query<DynamicUser>(); }
}

public IQueryable<PatientRecord> PatientRecords
{
get { return _session.Query<PatientRecord>(); }
Expand Down
1 change: 1 addition & 0 deletions src/NHibernate.DomainModel/Northwind/Entities/Role.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ public class Role
public virtual bool IsActive { get; set; }
public virtual AnotherEntity Entity { get; set; }
public virtual Role ParentRole { get; set; }
public virtual User CreatedBy { get; set; } // Not mapped
}
}
6 changes: 6 additions & 0 deletions src/NHibernate.DomainModel/Northwind/Entities/User.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,16 @@ public class User : IUser, IEntity

public virtual FeatureSet Features { get; set; }

public virtual User NotMappedUser => this;

public virtual EnumStoredAsString Enum1 { get; set; }

public virtual EnumStoredAsString? NullableEnum1 { get; set; }

public virtual EnumStoredAsInt32 Enum2 { get; set; }

public virtual EnumStoredAsInt32? NullableEnum2 { get; set; }

public virtual IUser CreatedBy { get; set; }

public virtual IUser ModifiedBy { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@ public class UserComponent
public string Property1 { get; set; }
public string Property2 { get; set; }
public UserComponent2 OtherComponent { get; set; }

public string Property3 => $"{Property1}{Property2}";
}

public class UserComponent2
{
public string OtherProperty1 { get; set; }

public string OtherProperty2 => OtherProperty1;
}
}
}
3 changes: 3 additions & 0 deletions src/NHibernate.DomainModel/Northwind/Entities/UserDto.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;

namespace NHibernate.DomainModel.Northwind.Entities
{
Expand All @@ -9,11 +10,13 @@ public class UserDto
public virtual int InvalidLoginAttempts { get; set; }
public virtual string RoleName { get; set; }
public virtual UserDto2 Dto2 { get; set; }
public virtual List<UserDto2> Dto2List { get; set; } = new List<UserDto2>();

public UserDto(int id, string name)
{
Id = id;
Name = name;
Dto2 = new UserDto2();
}
}

Expand Down
30 changes: 30 additions & 0 deletions src/NHibernate.DomainModel/Northwind/Mappings/DynamicUser.hbm.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="NHibernate.DomainModel.Northwind.Entities" assembly="NHibernate.DomainModel">
<class name="DynamicUser" mutable="false">
<subselect>
select * from Users
</subselect>

<id name="Id" column="UserId" type="Int32">
<generator class="assigned" />
</id>

<dynamic-component name="Properties">
<property name="Name" type="AnsiString" />
<property name="Enum1" type="NHibernate.DomainModel.Northwind.Entities.EnumStoredAsStringType, NHibernate.DomainModel">
<column name="Enum1" length="12" />
</property>
<many-to-one name="CreatedBy" class="User" not-null="true" lazy="false">
<column name="CreatedById" not-null="true" />
</many-to-one>
</dynamic-component>

<dynamic-component name="Settings">
<property name="Property1" type="AnsiString" />
<property name="Property2" type="AnsiString" />
<many-to-one name="ModifiedBy" class="User" lazy="false">
<column name="ModifiedById" />
</many-to-one>
</dynamic-component>
</class>
</hibernate-mapping>
6 changes: 6 additions & 0 deletions src/NHibernate.DomainModel/Northwind/Mappings/User.hbm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,14 @@
<column name="Enum1" length="12" />
</property>

<property name="NullableEnum1" type="NHibernate.DomainModel.Northwind.Entities.EnumStoredAsStringType, NHibernate.DomainModel"
formula="(case when Enum1 = 'Unspecified' then null else Enum1 end)" insert="false" update="false">
</property>

<property name="Enum2" not-null="true" />

<property name="NullableEnum2" formula="(case when Enum2 = 0 then null else Enum2 end)" insert="false" update="false" />

<property name="Features" not-null="true" />

<many-to-one name="Role" class="Role">
Expand Down
37 changes: 37 additions & 0 deletions src/NHibernate.Test/Async/Linq/EnumTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,42 @@ public async Task CanQueryOnEnumStoredAsString_Small_1Async()

Assert.AreEqual(expectedCount, query.Count);
}

[Test]
public async Task ConditionalNavigationPropertyAsync()
{
EnumStoredAsString? type = null;
await (db.Users.Where(o => o.Enum1 == EnumStoredAsString.Large).ToListAsync());
await (db.Users.Where(o => EnumStoredAsString.Large != o.Enum1).ToListAsync());
await (db.Users.Where(o => (o.NullableEnum1 ?? EnumStoredAsString.Large) == EnumStoredAsString.Medium).ToListAsync());
await (db.Users.Where(o => ((o.NullableEnum1 ?? type) ?? o.Enum1) == EnumStoredAsString.Medium).ToListAsync());

await (db.Users.Where(o => (o.NullableEnum1.HasValue ? o.Enum1 : EnumStoredAsString.Unspecified) == EnumStoredAsString.Medium).ToListAsync());
await (db.Users.Where(o => (o.Enum1 != EnumStoredAsString.Large
? (o.NullableEnum1.HasValue ? o.Enum1 : EnumStoredAsString.Unspecified)
: EnumStoredAsString.Small) == EnumStoredAsString.Medium).ToListAsync());

await (db.Users.Where(o => (o.Enum1 == EnumStoredAsString.Large ? o.Role : o.Role).Name == "test").ToListAsync());
}

[Test]
public async Task CanQueryComplexExpressionOnEnumStoredAsStringAsync()
{
var type = EnumStoredAsString.Unspecified;
var query = await ((from user in db.Users
where (user.NullableEnum1 == EnumStoredAsString.Large
? EnumStoredAsString.Medium
: user.NullableEnum1 ?? user.Enum1
) == type
select new
{
user,
simple = user.Enum1,
condition = user.Enum1 == EnumStoredAsString.Large ? EnumStoredAsString.Medium : user.Enum1,
coalesce = user.NullableEnum1 ?? EnumStoredAsString.Medium
}).ToListAsync());

Assert.That(query.Count, Is.EqualTo(0));
}
}
}
28 changes: 28 additions & 0 deletions src/NHibernate.Test/Async/Linq/ParameterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,34 @@ public async Task UsingTwoEntityParametersAsync()
2));
}

[Test]
public async Task UsingEntityEnumerableParameterTwiceAsync()
{
if (!Dialect.SupportsSubSelects)
{
Assert.Ignore();
}

var enumerable = await (db.DynamicUsers.FirstAsync());
await (AssertTotalParametersAsync(
db.DynamicUsers.Where(o => o == enumerable && o != enumerable),
1));
}

[Test]
public async Task UsingEntityEnumerableListParameterTwiceAsync()
{
if (!Dialect.SupportsSubSelects)
{
Assert.Ignore();
}

var enumerable = new[] {await (db.DynamicUsers.FirstAsync())};
await (AssertTotalParametersAsync(
db.DynamicUsers.Where(o => enumerable.Contains(o) && enumerable.Contains(o)),
1));
}

[Test]
public async Task UsingValueTypeParameterTwiceAsync()
{
Expand Down
Loading