Skip to content

NH-3435 #299

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

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added lib/net/Microsoft.Data.Services.dll
Binary file not shown.
28,163 changes: 28,163 additions & 0 deletions lib/net/Microsoft.Data.Services.xml

Large diffs are not rendered by default.

77 changes: 77 additions & 0 deletions src/NHibernate.Test/Criteria/ProjectionsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using NHibernate.Criterion;
using NHibernate.Dialect;
using NHibernate.SqlCommand;
using NUnit.Framework;

namespace NHibernate.Test.Criteria
Expand Down Expand Up @@ -347,6 +348,82 @@ public void UseNotEqPropertyWithProjection()
}
}

[Test]
public void UseRootProjection()
{
//NH-3435
using (ISession session = sessions.OpenSession())
using (ITransaction tx = session.BeginTransaction())
{
Course course = new Course();
course.CourseCode = "HIB";
course.Description = "Hibernate Training";
session.Save(course);

Student gavin = new Student();
gavin.Name = "Gavin King";
gavin.StudentNumber = 667;
session.Save(gavin);

Enrolment enrolment = new Enrolment();
enrolment.Course = course;
enrolment.CourseCode = course.CourseCode;
enrolment.Semester = 1;
enrolment.Year = 1999;
enrolment.Student = gavin;
enrolment.StudentNumber = gavin.StudentNumber;
gavin.Enrolments.Add(enrolment);
session.Save(enrolment);

session.Flush();

Student g = session.CreateCriteria(typeof(Student))
.Add(Expression.IdEq(gavin.StudentNumber))
.SetFetchMode("Enrolments", FetchMode.Join)
.SetProjection(Projections.RootEntity())
.UniqueResult<Student>();

Assert.AreSame(gavin, g);
}
}

[Test]
public void UseEntityProjection()
{
//NH-3435
using (ISession session = sessions.OpenSession())
using (ITransaction tx = session.BeginTransaction())
{
Course course = new Course();
course.CourseCode = "HIB";
course.Description = "Hibernate Training";
session.Save(course);

Student gavin = new Student();
gavin.Name = "Gavin King";
gavin.StudentNumber = 667;
session.Save(gavin);

Enrolment enrolment = new Enrolment();
enrolment.Course = course;
enrolment.CourseCode = course.CourseCode;
enrolment.Semester = 1;
enrolment.Year = 1999;
enrolment.Student = gavin;
enrolment.StudentNumber = gavin.StudentNumber;
gavin.Enrolments.Add(enrolment);
session.Save(enrolment);

session.Flush();

Student g = session.CreateCriteria(typeof(Enrolment))
.Add(Expression.And(Expression.Eq("StudentNumber", gavin.StudentNumber), Expression.Eq("CourseCode", course.CourseCode)))
.CreateAlias("Student", "s", JoinType.InnerJoin)
.SetProjection(Projections.Entity<Student>("s"))
.UniqueResult<Student>();

Assert.AreSame(gavin, g);
}
}
}
}
35 changes: 35 additions & 0 deletions src/NHibernate.Test/Linq/QueryAsReadOnlyTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.Linq;
using NHibernate.AdoNet;
using NHibernate.Cfg;
using NHibernate.Engine;
using NHibernate.Linq;
using NUnit.Framework;

namespace NHibernate.Test.Linq
{
public class QueryAsReadOnlyTests : LinqTestCase
{
[Test]
public void CanSetReadOnlyOnSimpeLinqQueries()
{
//NH-3658
var result = (from e in db.Customers
where e.CompanyName == "Corp"
select e).AsReadOnly().ToList();

Assert.IsTrue(result.All(x => session.IsReadOnly(x)));
}

[Test]
public void CanSetReadOnlyOnComplexLinqQueries()
{
//NH-3658
var result = (from e in db.Customers
where e.CompanyName == "Corp"
orderby e.ContactName
select e).Skip(1).Take(10).AsReadOnly().ToList();

Assert.IsTrue(result.All(x => session.IsReadOnly(x)));
}
}
}
5 changes: 3 additions & 2 deletions src/NHibernate.Test/NHibernate.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,7 @@
<Compile Include="Linq\DateTimeTests.cs" />
<Compile Include="Linq\ExpressionSessionLeakTest.cs" />
<Compile Include="Linq\LoggingTests.cs" />
<Compile Include="Linq\QueryAsReadOnlyTests.cs" />
<Compile Include="Linq\QueryTimeoutTests.cs" />
<Compile Include="Linq\JoinTests.cs" />
<Compile Include="Linq\CustomExtensionsExample.cs" />
Expand All @@ -529,7 +530,7 @@
<Compile Include="Linq\ExtensionMethods.cs" />
<Compile Include="Linq\FunctionTests.cs" />
<Compile Include="Linq\LinqQuerySamples.cs" />
<Compile Include="Linq\LinqReadonlyTestsContext.cs" />
<Compile Include="Linq\LinqReadOnlyTestsContext.cs" />
<Compile Include="Linq\LinqTestCase.cs" />
<Compile Include="Linq\LinqToHqlGeneratorsRegistryFactoryTest.cs" />
<Compile Include="Linq\MethodCallTests.cs" />
Expand Down Expand Up @@ -3630,4 +3631,4 @@ if exist hibernate.cfg.xml (del hibernate.cfg.xml)
if exist "$(ProjectDir)hibernate.cfg.xml" (copy "$(ProjectDir)hibernate.cfg.xml" "hibernate.cfg.xml")
copy /y "..\..\..\NHibernate.DomainModel\ABC.hbm.xml" "ABC.hbm.xml"</PostBuildEvent>
</PropertyGroup>
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Data.Services">
<HintPath>..\..\lib\net\Microsoft.Data.Services.dll</HintPath>
</Reference>
<Reference Include="FirebirdSql.Data.FirebirdClient">
<HintPath>..\..\lib\teamcity\firebird\FirebirdSql.Data.FirebirdClient.dll</HintPath>
</Reference>
Expand Down
1 change: 1 addition & 0 deletions src/NHibernate.TestDatabaseSetup/TestDatabaseSetup.build
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<include name="FirebirdSql.Data.FirebirdClient.dll" />
<include name="System.Data.SqlServerCe.dll" />
<include name="Npgsql.dll" />
<include name="Microsoft.Data.Services.dll" />
</assemblyfileset>
</target>
<target name="generate-assemblyinfo" depends="init common.generate-assemblyinfo" />
Expand Down
127 changes: 127 additions & 0 deletions src/NHibernate/Criterion/BaseEntityProjection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NHibernate;
using NHibernate.Criterion;
using NHibernate.Engine;
using NHibernate.Persister.Entity;
using NHibernate.SqlCommand;
using NHibernate.Type;

namespace NHibernate.Criterion
{
[Serializable]
public abstract class BaseEntityProjection : IProjection
{
private string alias = null;
private string [] columnAliases = null;
private bool lazy = true;

protected BaseEntityProjection(System.Type rootEntity, string alias)
{
this.RootEntity = rootEntity;
this.alias = alias;
}

protected System.Type RootEntity
{
get;
private set;
}

public BaseEntityProjection SetLazy(bool lazy)
{
this.lazy = lazy;

return (this);
}

string[] IProjection.Aliases
{
get
{
return (this.columnAliases.ToArray());
}
}

TypedValue[] IProjection.GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
throw new NotImplementedException();
}

IType[] IProjection.GetTypes(string alias, ICriteria criteria, ICriteriaQuery criteriaQuery)
{
return (new IType[] { criteriaQuery.GetType(criteria, alias) });
}

private void SetFields(ICriteria criteria)
{
if (this.RootEntity == null)
{
this.RootEntity = criteria.GetRootEntityTypeIfAvailable();
}

if (this.alias == null)
{
this.alias = criteria.Alias;
}
}

IType[] IProjection.GetTypes(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
this.SetFields(criteria);

return (new IType[] { new ManyToOneType(this.RootEntity.FullName, this.lazy) });
}

bool IProjection.IsAggregate
{
get { return (false); }
}

bool IProjection.IsGrouped
{
get { return (false); }
}

SqlString IProjection.ToGroupSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery, IDictionary<string, IFilter> enabledFilters)
{
throw new NotImplementedException();
}

SqlString IProjection.ToSqlString(ICriteria criteria, int position, ICriteriaQuery criteriaQuery, IDictionary<string, IFilter> enabledFilters)
{
this.SetFields(criteria);

SqlStringBuilder builder = new SqlStringBuilder();
AbstractEntityPersister persister = criteriaQuery.Factory.TryGetEntityPersister(this.RootEntity.FullName) as AbstractEntityPersister;
ICriteria subcriteria = criteria.GetCriteriaByAlias(this.alias);

this.columnAliases = persister.GetIdentifierAliases(string.Empty);

string[] columnNames = persister.GetPropertyColumnNames(persister.IdentifierPropertyName).Select(x => string.Concat(criteriaQuery.GetSQLAlias(subcriteria, persister.IdentifierPropertyName), ".", criteriaQuery.Factory.Dialect.QuoteForColumnName(x))).ToArray();

for (int i = 0; i < columnNames.Length; ++i)
{
builder.Add(String.Format("{0} as {1}", columnNames[i], this.columnAliases[i]));

if (i < columnNames.Length - 1)
{
builder.Add(", ");
}
}

return (builder.ToSqlString());
}

public string[] GetColumnAliases(int position, ICriteria criteria, ICriteriaQuery criteriaQuery)
{
return ((this as IProjection).Aliases);
}

public string[] GetColumnAliases(string alias, int position, ICriteria criteria, ICriteriaQuery criteriaQuery)
{
return ((this as IProjection).Aliases);
}
}
}
20 changes: 20 additions & 0 deletions src/NHibernate/Criterion/EntityProjection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;

namespace NHibernate.Criterion
{
[Serializable]
public class EntityProjection : BaseEntityProjection
{
public EntityProjection(System.Type rootEntity, String alias) : base(rootEntity, alias)
{
}
}

[Serializable]
public class EntityProjection<T> : EntityProjection
{
public EntityProjection(String alias) : base(typeof(T), alias)
{
}
}
}
25 changes: 25 additions & 0 deletions src/NHibernate/Criterion/Projections.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,31 @@ namespace NHibernate.Criterion
/// </summary>
public static class Projections
{
/// <summary>
/// Return the root entity.
/// </summary>
/// <returns>The root entity.</returns>
public static IProjection RootEntity()
{
return (new RootEntityProjection());
}

/// <summary>
/// Return an aliased entity.
/// </summary>
/// <param name="type">The type of the entity.</param>
/// <param name="alias">The alias of the entity.</param>
/// <returns>A projection of the entity.</returns>
public static IProjection Entity(System.Type type, string alias)
{
return (new EntityProjection(type, alias));
}

public static IProjection Entity<T>(string alias)
{
return (new EntityProjection<T>(alias));
}

/// <summary>
/// Create a distinct projection from a projection
/// </summary>
Expand Down
12 changes: 12 additions & 0 deletions src/NHibernate/Criterion/RootEntityProjection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;

namespace NHibernate.Criterion
{
[Serializable]
public class RootEntityProjection : BaseEntityProjection
{
public RootEntityProjection() : base(null, null)
{
}
}
}
1 change: 1 addition & 0 deletions src/NHibernate/Linq/GroupBy/AggregatingGroupByRewriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public static class AggregatingGroupByRewriter
typeof (AnyResultOperator),
typeof (AllResultOperator),
typeof (TimeoutResultOperator),
typeof (AsReadOnlyResultOperator),
};

public static void ReWrite(QueryModel queryModel)
Expand Down
9 changes: 9 additions & 0 deletions src/NHibernate/Linq/LinqExtensionMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ public static IQueryable<T> Query<T>(this IStatelessSession session)
return new NhQueryable<T>(session.GetSessionImplementation());
}

public static IQueryable<T> AsReadOnly<T>(this IQueryable<T> query)
{
var method = ReflectionHelper.GetMethodDefinition(() => AsReadOnly<object>(null)).MakeGenericMethod(typeof(T));

var callExpression = Expression.Call(method, query.Expression);

return new NhQueryable<T>(query.Provider, callExpression);
}

public static IQueryable<T> Cacheable<T>(this IQueryable<T> query)
{
var method = ReflectionHelper.GetMethodDefinition(() => Cacheable<object>(null)).MakeGenericMethod(typeof (T));
Expand Down
Loading