From: <ste...@us...> - 2009-08-13 11:56:52
|
Revision: 4689 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4689&view=rev Author: steverstrong Date: 2009-08-13 11:56:42 +0000 (Thu, 13 Aug 2009) Log Message: ----------- Added initial test for Linq provider to show the approach taken to integrate with the core Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Engine/ISessionImplementor.cs trunk/nhibernate/src/NHibernate/Engine/Query/HQLQueryPlan.cs trunk/nhibernate/src/NHibernate/Engine/Query/QueryPlanCache.cs trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/ASTQueryTranslatorFactory.cs trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs trunk/nhibernate/src/NHibernate/Hql/IQueryTranslatorFactory.cs trunk/nhibernate/src/NHibernate/ISession.cs trunk/nhibernate/src/NHibernate/Impl/AbstractSessionImpl.cs trunk/nhibernate/src/NHibernate/Impl/QueryImpl.cs trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs trunk/nhibernate/src/NHibernate/Impl/StatelessSessionImpl.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate/IQueryExpression.cs trunk/nhibernate/src/NHibernate/Linq/ trunk/nhibernate/src/NHibernate/Linq/LinqExpression.cs trunk/nhibernate/src/NHibernate/Linq/LinqExtensionMethods.cs trunk/nhibernate/src/NHibernate/Linq/NhQueryProvider.cs trunk/nhibernate/src/NHibernate/Linq/Query.cs trunk/nhibernate/src/NHibernate/Linq/QueryProvider.cs trunk/nhibernate/src/NHibernate/Linq/TypeHelper.cs trunk/nhibernate/src/NHibernate.Test/Linq/ trunk/nhibernate/src/NHibernate.Test/Linq/BasicLinqTests.cs trunk/nhibernate/src/NHibernate.Test/Linq/Entities/ trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Address.cs trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Customer.cs trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Employee.cs trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Entity.cs trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Northwind.cs trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Order.cs trunk/nhibernate/src/NHibernate.Test/Linq/Entities/OrderLine.cs trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Product.cs trunk/nhibernate/src/NHibernate.Test/Linq/Entities/ProductCategory.cs trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Region.cs trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Shipper.cs trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Supplier.cs trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Territory.cs trunk/nhibernate/src/NHibernate.Test/Linq/LinqTestCase.cs trunk/nhibernate/src/NHibernate.Test/Linq/Mappings/ trunk/nhibernate/src/NHibernate.Test/Linq/Mappings/Customer.hbm.xml trunk/nhibernate/src/NHibernate.Test/Linq/Mappings/Employee.hbm.xml trunk/nhibernate/src/NHibernate.Test/Linq/Mappings/Order.hbm.xml trunk/nhibernate/src/NHibernate.Test/Linq/Mappings/OrderLine.hbm.xml trunk/nhibernate/src/NHibernate.Test/Linq/Mappings/Product.hbm.xml trunk/nhibernate/src/NHibernate.Test/Linq/Mappings/ProductCategory.hbm.xml trunk/nhibernate/src/NHibernate.Test/Linq/Mappings/Region.hbm.xml trunk/nhibernate/src/NHibernate.Test/Linq/Mappings/Shipper.hbm.xml trunk/nhibernate/src/NHibernate.Test/Linq/Mappings/Supplier.hbm.xml trunk/nhibernate/src/NHibernate.Test/Linq/Mappings/Territory.hbm.xml Property Changed: ---------------- trunk/nhibernate/src/ trunk/nhibernate/src/NHibernate/ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Generated/ trunk/nhibernate/src/NHibernate.ByteCode.LinFu/ trunk/nhibernate/src/NHibernate.ByteCode.LinFu.Tests/ trunk/nhibernate/src/NHibernate.DomainModel/ trunk/nhibernate/src/NHibernate.Test/ Property changes on: trunk/nhibernate/src ___________________________________________________________________ Modified: svn:ignore - *.suo CloverSrc _ReSharper* *.resharperoptions *.resharper.user CloverBuild Ankh.Load *.resharper ConsoleTest + *.suo CloverSrc _ReSharper* *.resharperoptions *.resharper.user CloverBuild Ankh.Load *.resharper ConsoleTest _UpgradeReport_Files NHibernate.userprefs NHibernate.usertasks UpgradeLog.XML UpgradeLog2.XML UpgradeLog3.XML UpgradeLog4.XML UpgradeLog5.XML UpgradeLog6.XML UpgradeLog7.XML UpgradeLog8.XML UpgradeLog9.XML NHibernate.sln.proj NHibernate.sln.AssemblySurfaceCache.user NHibernate.sln.cache Property changes on: trunk/nhibernate/src/NHibernate ___________________________________________________________________ Modified: svn:ignore - obj .#* *.user *.xsx AssemblyInfo.cs *.aps *.eto [Bb]in [Dd]ebug [Rr]elease *resharper* + obj .#* *.user *.xsx AssemblyInfo.cs *.aps *.eto [Bb]in [Dd]ebug [Rr]elease *resharper* _ReSharper.NHibernate NHibernate.pidb Modified: trunk/nhibernate/src/NHibernate/Engine/ISessionImplementor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/ISessionImplementor.cs 2009-08-10 15:41:06 UTC (rev 4688) +++ trunk/nhibernate/src/NHibernate/Engine/ISessionImplementor.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -81,6 +81,14 @@ /// <returns></returns> IList List(string query, QueryParameters parameters); + /// <summary> + /// Execute a <c>List()</c> expression query + /// </summary> + /// <param name="queryExpression"></param> + /// <param name="parameters"></param> + /// <returns></returns> + IList List(IQueryExpression queryExpression, QueryParameters parameters); + void List(string query, QueryParameters parameters, IList results); /// <summary> Modified: trunk/nhibernate/src/NHibernate/Engine/Query/HQLQueryPlan.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/Query/HQLQueryPlan.cs 2009-08-10 15:41:06 UTC (rev 4688) +++ trunk/nhibernate/src/NHibernate/Engine/Query/HQLQueryPlan.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -6,6 +6,7 @@ using log4net; using NHibernate.Event; using NHibernate.Hql; +using NHibernate.Hql.Ast.ANTLR; using NHibernate.Type; using NHibernate.Util; @@ -30,10 +31,16 @@ public HQLQueryPlan(string hql, bool shallow, IDictionary<string, IFilter> enabledFilters, ISessionFactoryImplementor factory) - : this(hql, null, shallow, enabledFilters, factory) + : this(hql, (string) null, shallow, enabledFilters, factory) { } + public HQLQueryPlan(string expressionStr, IQueryExpression queryExpression, bool shallow, + IDictionary<string, IFilter> enabledFilters, ISessionFactoryImplementor factory) + : this(expressionStr, queryExpression, null, shallow, enabledFilters, factory) + { + } + protected internal HQLQueryPlan(string hql, string collectionRole, bool shallow, IDictionary<string, IFilter> enabledFilters, ISessionFactoryImplementor factory) { @@ -98,9 +105,39 @@ } } } - } + protected internal HQLQueryPlan(string expressionStr, IQueryExpression queryExpression, string collectionRole, bool shallow, + IDictionary<string, IFilter> enabledFilters, ISessionFactoryImplementor factory) + { + sourceQuery = expressionStr; + this.shallow = shallow; + + enabledFilterNames = new HashedSet<string>(enabledFilters.Keys); + + // TODO - no support for polymorphism here - done during Expression -> AST translation? + // TODO - polymorphism approach used in method above also sucks. Could be done in AST much more cleanly? Look at this... + IQueryTranslatorFactory2 qtFactory = new ASTQueryTranslatorFactory(); + + IQueryTranslator translator = qtFactory.CreateQueryTranslator(expressionStr, queryExpression, enabledFilters, + factory); + + translator.Compile(factory.Settings.QuerySubstitutions, shallow); + + translators = new[] { translator }; + + sqlStrings = new List<string>(translator.CollectSqlStrings).ToArray(); + + querySpaces = new HashedSet<string>(translator.QuerySpaces); + + // TODO - need to build parameterMetadata. Current function no good, since is parses the HQL. Might need to walk the AST here, + // probably inside the QueryTranslator. That's probably a better place for the parsing to be anyway; possibly worth moving for classic as well... + //parameterMetadata = BuildParameterMetadata(translator.GetParameterTranslations(), hql); + parameterMetadata = new ParameterMetadata(new OrdinalParameterDescriptor[0], new Dictionary<string, NamedParameterDescriptor>()); + + returnMetadata = new ReturnMetadata(translator.ReturnAliases, translator.ReturnTypes); + } + public string SourceQuery { get { return sourceQuery; } Modified: trunk/nhibernate/src/NHibernate/Engine/Query/QueryPlanCache.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/Query/QueryPlanCache.cs 2009-08-10 15:41:06 UTC (rev 4688) +++ trunk/nhibernate/src/NHibernate/Engine/Query/QueryPlanCache.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -72,6 +72,35 @@ return plan; } + public HQLQueryPlan GetHQLQueryPlan(IQueryExpression queryExpression, bool shallow, IDictionary<string, IFilter> enabledFilters) + { + string expressionStr = queryExpression.Key; + + var key = new HQLQueryPlanKey(expressionStr, shallow, enabledFilters); + var plan = (HQLQueryPlan)planCache[key]; + + if (plan == null) + { + if (log.IsDebugEnabled) + { + log.Debug("unable to locate HQL query plan in cache; generating (" + expressionStr + ")"); + } + plan = new HQLQueryPlan(expressionStr, queryExpression, shallow, enabledFilters, factory); + } + else + { + if (log.IsDebugEnabled) + { + log.Debug("located HQL query plan in cache (" + expressionStr + ")"); + } + } + + planCache.Put(key, plan); + + return plan; + } + + public FilterQueryPlan GetFilterQueryPlan(string filterString, string collectionRole, bool shallow, IDictionary<string, IFilter> enabledFilters) { var key = new FilterQueryPlanKey(filterString, collectionRole, shallow, enabledFilters); Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/ASTQueryTranslatorFactory.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/ASTQueryTranslatorFactory.cs 2009-08-10 15:41:06 UTC (rev 4688) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/ASTQueryTranslatorFactory.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -10,7 +10,7 @@ /// Author: Gavin King /// Ported by: Steve Strong /// </summary> - public class ASTQueryTranslatorFactory : IQueryTranslatorFactory + public class ASTQueryTranslatorFactory : IQueryTranslatorFactory2 { public IQueryTranslator CreateQueryTranslator(string queryIdentifier, string queryString, IDictionary<string, IFilter> filters, ISessionFactoryImplementor factory) { @@ -21,5 +21,10 @@ { return new QueryTranslatorImpl(queryIdentifier, queryString, filters, factory); } + + public IQueryTranslator CreateQueryTranslator(string queryIdentifier, IQueryExpression queryExpression, IDictionary<string, IFilter> filters, ISessionFactoryImplementor factory) + { + return new QueryTranslatorImpl(queryIdentifier, queryExpression, filters, factory); + } } } Property changes on: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/Generated ___________________________________________________________________ Added: svn:ignore + Hql.tokens HqlSqlWalker.tokens SqlGenerator.tokens Modified: trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs 2009-08-10 15:41:06 UTC (rev 4688) +++ trunk/nhibernate/src/NHibernate/Hql/Ast/ANTLR/QueryTranslatorImpl.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -58,6 +58,28 @@ _factory = factory; } + /// <summary> + /// Creates a new AST-based query translator. + /// </summary> + /// <param name="queryIdentifier">The query-identifier (used in stats collection)</param> + /// <param name="queryExpression">The hql query to translate</param> + /// <param name="enabledFilters">Currently enabled filters</param> + /// <param name="factory">The session factory constructing this translator instance.</param> + public QueryTranslatorImpl( + string queryIdentifier, + IQueryExpression queryExpression, + IDictionary<string, IFilter> enabledFilters, + ISessionFactoryImplementor factory) + { + _queryIdentifier = queryIdentifier; + _hql = queryExpression.ToString(); + _compiled = false; + _shallowQuery = false; + _enabledFilters = enabledFilters; + _factory = factory; + _parser = new HqlParseEngine(queryExpression.Translate(factory), factory); + } + /// <summary> /// Compile a "normal" query. This method may be called multiple /// times. Subsequent invocations are no-ops. Modified: trunk/nhibernate/src/NHibernate/Hql/IQueryTranslatorFactory.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Hql/IQueryTranslatorFactory.cs 2009-08-10 15:41:06 UTC (rev 4688) +++ trunk/nhibernate/src/NHibernate/Hql/IQueryTranslatorFactory.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -39,4 +39,26 @@ /// <returns>An appropriate translator.</returns> IFilterTranslator CreateFilterTranslator(string queryIdentifier, string queryString, IDictionary<string, IFilter> filters, ISessionFactoryImplementor factory); } + + /// <summary> + /// Facade for generation of <see cref="NHibernate.Hql.IQueryTranslator"/> + /// and <see cref="NHibernate.Hql.IFilterTranslator"/> instances. + /// </summary> + public interface IQueryTranslatorFactory2 : IQueryTranslatorFactory + { + /// <summary> + /// Construct a <see cref="NHibernate.Hql.IQueryTranslator"/> instance + /// capable of translating a Linq expression. + /// </summary> + /// <param name="queryIdentifier"> + /// The query-identifier (used in <see cref="NHibernate.Stat.QueryStatistics"/> collection). + /// This is typically the same as the queryString parameter except for the case of + /// split polymorphic queries which result in multiple physical sql queries. + /// </param> + /// <param name="queryExpression">The query expression to be translated</param> + /// <param name="filters">Currently enabled filters</param> + /// <param name="factory">The session factory</param> + /// <returns>An appropriate translator.</returns> + IQueryTranslator CreateQueryTranslator(string queryIdentifier, IQueryExpression queryExpression, IDictionary<string, IFilter> filters, ISessionFactoryImplementor factory); + } } \ No newline at end of file Added: trunk/nhibernate/src/NHibernate/IQueryExpression.cs =================================================================== --- trunk/nhibernate/src/NHibernate/IQueryExpression.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/IQueryExpression.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -0,0 +1,11 @@ +using NHibernate.Hql.Ast.ANTLR.Tree; + +namespace NHibernate +{ + public interface IQueryExpression + { + IASTNode Translate(ISessionFactory sessionFactory); + string Key { get; } + System.Type Type { get; } + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate/IQueryExpression.cs ___________________________________________________________________ Added: svn:executable + * Modified: trunk/nhibernate/src/NHibernate/ISession.cs =================================================================== --- trunk/nhibernate/src/NHibernate/ISession.cs 2009-08-10 15:41:06 UTC (rev 4688) +++ trunk/nhibernate/src/NHibernate/ISession.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -804,6 +804,13 @@ /// <returns>The query</returns> IQuery CreateQuery(string queryString); + /// <summary> + /// Create a new instance of <c>Query</c> for the given query expression + /// <param name="queryExpression"/>A hibernate query expression</param> + /// <returns>The query</returns> + /// </summary> + IQuery CreateQuery(IQueryExpression queryExpression); + /// <summary> /// Create a new instance of <c>Query</c> for the given collection and filter string /// </summary> Modified: trunk/nhibernate/src/NHibernate/Impl/AbstractSessionImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/AbstractSessionImpl.cs 2009-08-10 15:41:06 UTC (rev 4688) +++ trunk/nhibernate/src/NHibernate/Impl/AbstractSessionImpl.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -76,6 +76,8 @@ public abstract void CloseSessionFromDistributedTransaction(); public abstract IList List(string query, QueryParameters parameters); public abstract void List(string query, QueryParameters parameters, IList results); + public abstract IList List(IQueryExpression queryExpression, QueryParameters parameters); + public abstract void List(IQueryExpression queryExpression, QueryParameters queryParameters, IList results); public abstract IList<T> List<T>(string query, QueryParameters queryParameters); public abstract IList<T> List<T>(CriteriaImpl criteria); public abstract void List(CriteriaImpl criteria, IList results); @@ -245,6 +247,18 @@ } } + public virtual IQuery CreateQuery(IQueryExpression queryExpression) + { + using (new SessionIdLoggingContext(SessionId)) + { + CheckAndUpdateSessionStatus(); + QueryImpl query = new QueryImpl(queryExpression, this, + GetHQLQueryPlan(queryExpression, false).ParameterMetadata); + query.SetComment("[expression]"); + return query; + } + } + public virtual IQuery CreateQuery(string queryString) { using (new SessionIdLoggingContext(SessionId)) @@ -275,6 +289,14 @@ } } + protected internal virtual HQLQueryPlan GetHQLQueryPlan(IQueryExpression queryExpression, bool shallow) + { + using (new SessionIdLoggingContext(SessionId)) + { + return factory.QueryPlanCache.GetHQLQueryPlan(queryExpression, shallow, EnabledFilters); + } + } + protected internal virtual NativeSQLQueryPlan GetNativeSQLQueryPlan(NativeSQLQuerySpecification spec) { using (new SessionIdLoggingContext(SessionId)) Modified: trunk/nhibernate/src/NHibernate/Impl/QueryImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/QueryImpl.cs 2009-08-10 15:41:06 UTC (rev 4688) +++ trunk/nhibernate/src/NHibernate/Impl/QueryImpl.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -13,6 +13,7 @@ public class QueryImpl : AbstractQueryImpl { private readonly Dictionary<string, LockMode> lockModes = new Dictionary<string, LockMode>(2); + private readonly IQueryExpression _queryExpression; public QueryImpl(string queryString, FlushMode flushMode, ISessionImplementor session, ParameterMetadata parameterMetadata) : base(queryString, flushMode, session, parameterMetadata) @@ -24,6 +25,12 @@ { } + public QueryImpl(IQueryExpression queryExpression, ISessionImplementor session, ParameterMetadata parameterMetadata) + : base(queryExpression.Key, FlushMode.Unspecified, session, parameterMetadata) + { + _queryExpression = queryExpression; + } + public override IEnumerable Enumerable() { VerifyParameters(); @@ -61,7 +68,14 @@ Before(); try { - return Session.List(ExpandParameterLists(namedParams), GetQueryParameters(namedParams)); + if (_queryExpression == null) + { + return Session.List(ExpandParameterLists(namedParams), GetQueryParameters(namedParams)); + } + else + { + return Session.List(_queryExpression, GetQueryParameters(namedParams)); + } } finally { Modified: trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs 2009-08-10 15:41:06 UTC (rev 4688) +++ trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -645,6 +645,50 @@ } } + public override IList List(IQueryExpression queryExpression, QueryParameters parameters) + { + IList results = (IList) typeof(List<>).MakeGenericType(queryExpression.Type) + .GetConstructor(System.Type.EmptyTypes) + .Invoke(null); + + List(queryExpression, parameters, results); + + return results; + } + + public override void List(IQueryExpression queryExpression, QueryParameters queryParameters, IList results) + { + using (new SessionIdLoggingContext(SessionId)) + { + CheckAndUpdateSessionStatus(); + queryParameters.ValidateParameters(); + HQLQueryPlan plan = GetHQLQueryPlan(queryExpression, false); + AutoFlushIfRequired(plan.QuerySpaces); + + bool success = false; + dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called + try + { + plan.PerformList(queryParameters, this, results); + success = true; + } + catch (HibernateException) + { + // Do not call Convert on HibernateExceptions + throw; + } + catch (Exception e) + { + throw Convert(e, "Could not execute query"); + } + finally + { + dontFlushFromFind--; + AfterOperation(success); + } + } + } + public override IQueryTranslator[] GetQueries(string query, bool scalar) { using (new SessionIdLoggingContext(SessionId)) Modified: trunk/nhibernate/src/NHibernate/Impl/StatelessSessionImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/StatelessSessionImpl.cs 2009-08-10 15:41:06 UTC (rev 4688) +++ trunk/nhibernate/src/NHibernate/Impl/StatelessSessionImpl.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -133,6 +133,16 @@ } } + public override IList List(IQueryExpression queryExpression, QueryParameters parameters) + { + throw new System.NotImplementedException(); + } + + public override void List(IQueryExpression queryExpression, QueryParameters queryParameters, IList results) + { + throw new System.NotImplementedException(); + } + public override IList<T> List<T>(string query, QueryParameters queryParameters) { using (new SessionIdLoggingContext(SessionId)) Added: trunk/nhibernate/src/NHibernate/Linq/LinqExpression.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/LinqExpression.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/LinqExpression.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -0,0 +1,41 @@ +using System; +using System.Linq.Expressions; +using NHibernate.Hql.Ast.ANTLR; +using NHibernate.Hql.Ast.ANTLR.Tree; + +namespace NHibernate.Linq +{ + class LinqExpression : IQueryExpression + { + private readonly Expression _linqExpression; + + internal LinqExpression(Expression linqExpression) + { + _linqExpression = linqExpression; + } + + public IASTNode Translate(ISessionFactory sessionFactory) + { + ASTFactory factory = new ASTFactory(new ASTTreeAdaptor()); + + return factory.CreateNode(HqlSqlWalker.QUERY, "query", + factory.CreateNode(HqlSqlWalker.SELECT_FROM, "select from", + factory.CreateNode(HqlSqlWalker.FROM, "from", + factory.CreateNode( + HqlSqlWalker.RANGE, "range", + factory.CreateNode( + HqlSqlWalker.IDENT, + "Product"))))); + } + + public string Key + { + get { return _linqExpression.ToString(); } + } + + public System.Type Type + { + get { return _linqExpression.Type.GetGenericArguments()[0]; } + } + } +} Property changes on: trunk/nhibernate/src/NHibernate/Linq/LinqExpression.cs ___________________________________________________________________ Added: svn:executable + * Added: trunk/nhibernate/src/NHibernate/Linq/LinqExtensionMethods.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/LinqExtensionMethods.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/LinqExtensionMethods.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -0,0 +1,12 @@ +using System.Linq; + +namespace NHibernate.Linq +{ + public static class ExtensionMethods + { + public static IQueryable<T> Query<T>(this ISession session) + { + return new Query<T>(new NhQueryProvider(session)); + } + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate/Linq/LinqExtensionMethods.cs ___________________________________________________________________ Added: svn:executable + * Added: trunk/nhibernate/src/NHibernate/Linq/NhQueryProvider.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/NhQueryProvider.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/NhQueryProvider.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -0,0 +1,20 @@ +using System.Linq.Expressions; + +namespace NHibernate.Linq +{ + public class NhQueryProvider : QueryProvider + { + private readonly ISession _session; + + public NhQueryProvider(ISession session) + { + _session = session; + } + + public override object Execute(Expression expression) + { + // walk the expression tree and build an HQL AST to mirror it + return _session.CreateQuery(new LinqExpression(expression)).List(); + } + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate/Linq/NhQueryProvider.cs ___________________________________________________________________ Added: svn:executable + * Added: trunk/nhibernate/src/NHibernate/Linq/Query.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Query.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Query.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -0,0 +1,85 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace NHibernate.Linq +{ + /// <summary> + /// A default implementation of IQueryable for use with QueryProvider + /// </summary> + public class Query<T> : IOrderedQueryable<T> + { + private readonly Expression _expression; + private readonly IQueryProvider _provider; + + public Query(IQueryProvider provider) + { + if (provider == null) + { + throw new ArgumentNullException("provider"); + } + _provider = provider; + _expression = Expression.Constant(this); + } + + public Query(IQueryProvider provider, Expression expression) + { + if (provider == null) + { + throw new ArgumentNullException("provider"); + } + if (expression == null) + { + throw new ArgumentNullException("expression"); + } + if (!typeof (IQueryable<T>).IsAssignableFrom(expression.Type)) + { + throw new ArgumentOutOfRangeException("expression"); + } + _provider = provider; + _expression = expression; + } + + #region IQueryable<T> Members + + public Expression Expression + { + get { return _expression; } + } + + public System.Type ElementType + { + get { return typeof (T); } + } + + public IQueryProvider Provider + { + get { return _provider; } + } + + public IEnumerator<T> GetEnumerator() + { + return ((IEnumerable<T>) _provider.Execute(_expression)).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable) _provider.Execute(_expression)).GetEnumerator(); + } + + #endregion + + public override string ToString() + { + if (_expression.NodeType == ExpressionType.Constant && + ((ConstantExpression) _expression).Value == this) + { + return "Query(" + typeof (T) + ")"; + } + + return _expression.ToString(); + } + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate/Linq/Query.cs ___________________________________________________________________ Added: svn:executable + * Added: trunk/nhibernate/src/NHibernate/Linq/QueryProvider.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/QueryProvider.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/QueryProvider.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -0,0 +1,49 @@ +using System; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace NHibernate.Linq +{ + /// <summary> + /// A basic abstract LINQ query provider + /// </summary> + public abstract class QueryProvider : IQueryProvider + { + #region IQueryProvider Members + + IQueryable<T> IQueryProvider.CreateQuery<T>(Expression expression) + { + return new Query<T>(this, expression); + } + + IQueryable IQueryProvider.CreateQuery(Expression expression) + { + System.Type elementType = TypeHelper.GetElementType(expression.Type); + try + { + return + (IQueryable) + Activator.CreateInstance(typeof (Query<>).MakeGenericType(elementType), new object[] {this, expression}); + } + catch (TargetInvocationException tie) + { + throw tie.InnerException; + } + } + + T IQueryProvider.Execute<T>(Expression expression) + { + return (T) Execute(expression); + } + + object IQueryProvider.Execute(Expression expression) + { + return Execute(expression); + } + + #endregion + + public abstract object Execute(Expression expression); + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate/Linq/QueryProvider.cs ___________________________________________________________________ Added: svn:executable + * Added: trunk/nhibernate/src/NHibernate/Linq/TypeHelper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/TypeHelper.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/TypeHelper.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -0,0 +1,127 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// This source code is made available under the terms of the Microsoft Public License (MS-PL) + +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; + +namespace NHibernate.Linq +{ + /// <summary> + /// Type related helper methods + /// </summary> + public static class TypeHelper + { + public static System.Type FindIEnumerable(System.Type seqType) + { + if (seqType == null || seqType == typeof (string)) + return null; + if (seqType.IsArray) + return typeof (IEnumerable<>).MakeGenericType(seqType.GetElementType()); + if (seqType.IsGenericType) + { + foreach (System.Type arg in seqType.GetGenericArguments()) + { + System.Type ienum = typeof (IEnumerable<>).MakeGenericType(arg); + if (ienum.IsAssignableFrom(seqType)) + { + return ienum; + } + } + } + System.Type[] ifaces = seqType.GetInterfaces(); + if (ifaces != null && ifaces.Length > 0) + { + foreach (System.Type iface in ifaces) + { + System.Type ienum = FindIEnumerable(iface); + if (ienum != null) return ienum; + } + } + if (seqType.BaseType != null && seqType.BaseType != typeof (object)) + { + return FindIEnumerable(seqType.BaseType); + } + return null; + } + + public static System.Type GetSequenceType(System.Type elementType) + { + return typeof (IEnumerable<>).MakeGenericType(elementType); + } + + public static System.Type GetElementType(System.Type seqType) + { + System.Type ienum = FindIEnumerable(seqType); + if (ienum == null) return seqType; + return ienum.GetGenericArguments()[0]; + } + + public static bool IsNullableType(System.Type type) + { + return type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof (Nullable<>); + } + + public static bool IsNullAssignable(System.Type type) + { + return !type.IsValueType || IsNullableType(type); + } + + public static System.Type GetNonNullableType(System.Type type) + { + if (IsNullableType(type)) + { + return type.GetGenericArguments()[0]; + } + return type; + } + + public static System.Type GetNullAssignableType(System.Type type) + { + if (!IsNullAssignable(type)) + { + return typeof (Nullable<>).MakeGenericType(type); + } + return type; + } + + public static ConstantExpression GetNullConstant(System.Type type) + { + return Expression.Constant(null, GetNullAssignableType(type)); + } + + public static System.Type GetMemberType(MemberInfo mi) + { + var fi = mi as FieldInfo; + if (fi != null) return fi.FieldType; + var pi = mi as PropertyInfo; + if (pi != null) return pi.PropertyType; + var ei = mi as EventInfo; + if (ei != null) return ei.EventHandlerType; + return null; + } + + public static object GetDefault(System.Type type) + { + bool isNullable = !type.IsValueType || IsNullableType(type); + if (!isNullable) + return Activator.CreateInstance(type); + return null; + } + + public static bool IsReadOnly(MemberInfo member) + { + switch (member.MemberType) + { + case MemberTypes.Field: + return (((FieldInfo) member).Attributes & FieldAttributes.InitOnly) != 0; + case MemberTypes.Property: + var pi = (PropertyInfo) member; + return !pi.CanWrite || pi.GetSetMethod() == null; + default: + return true; + } + } + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate/Linq/TypeHelper.cs ___________________________________________________________________ Added: svn:executable + * Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-08-10 15:41:06 UTC (rev 4688) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2009-08-13 11:56:42 UTC (rev 4689) @@ -544,10 +544,17 @@ <Compile Include="Hql\Ast\ANTLR\Tree\ASTErrorNode.cs" /> <Compile Include="Hql\Ast\ANTLR\Tree\InsertStatement.cs" /> <Compile Include="Hql\Ast\ANTLR\Tree\UpdateStatement.cs" /> + <Compile Include="IQueryExpression.cs" /> <Compile Include="IQueryOver.cs" /> <Compile Include="Criterion\QueryOver.cs" /> <Compile Include="Impl\ExpressionProcessor.cs" /> <Compile Include="Impl\SessionIdLoggingContext.cs" /> + <Compile Include="Linq\LinqExpression.cs" /> + <Compile Include="Linq\LinqExtensionMethods.cs" /> + <Compile Include="Linq\NhQueryProvider.cs" /> + <Compile Include="Linq\Query.cs" /> + <Compile Include="Linq\QueryProvider.cs" /> + <Compile Include="Linq\TypeHelper.cs" /> <Compile Include="Param\AbstractExplicitParameterSpecification.cs" /> <Compile Include="Param\AggregatedIndexCollectionSelectorParameterSpecifications.cs" /> <Compile Include="Param\CollectionFilterKeyParameterSpecification.cs" /> Property changes on: trunk/nhibernate/src/NHibernate.ByteCode.LinFu ___________________________________________________________________ Modified: svn:ignore - obj .#* *.user *.xsx AssemblyInfo.cs *.aps *.eto [Bb]in [Dd]ebug [Rr]elease *resharper* + obj .#* *.user *.xsx AssemblyInfo.cs *.aps *.eto [Bb]in [Dd]ebug [Rr]elease *resharper* NHibernate.ByteCode.LinFu.pidb Property changes on: trunk/nhibernate/src/NHibernate.ByteCode.LinFu.Tests ___________________________________________________________________ Modified: svn:ignore - obj .#* *.user *.xsx AssemblyInfo.cs hibernate.cfg.xml *.aps *.eto [Bb]in [Dd]ebug [Rr]elease *resharper* *.xml + obj .#* *.user *.xsx AssemblyInfo.cs hibernate.cfg.xml *.aps *.eto [Bb]in [Dd]ebug [Rr]elease *resharper* *.xml NHibernate.ByteCode.LinFu.Tests.pidb Property changes on: trunk/nhibernate/src/NHibernate.DomainModel ___________________________________________________________________ Modified: svn:ignore - bin obj .#* *.user *.xsx AssemblyInfo.cs [Bb]in [Dd]ebug [Rr]elease *.aps *.eto + bin obj .#* *.user *.xsx AssemblyInfo.cs [Bb]in [Dd]ebug [Rr]elease *.aps *.eto NHibernate.DomainModel.pidb Property changes on: trunk/nhibernate/src/NHibernate.Test ___________________________________________________________________ Modified: svn:ignore - bin obj .#* *.user *.xsx AssemblyInfo.cs hibernate.cfg.xml Debug Release *.aps *.eto [Bb]in [Dd]ebug [Rr]elease *resharper* *.xml + bin obj .#* *.user *.xsx AssemblyInfo.cs hibernate.cfg.xml Debug Release *.aps *.eto [Bb]in [Dd]ebug [Rr]elease *resharper* *.xml NHibernate.Test.pidb test-results Added: trunk/nhibernate/src/NHibernate.Test/Linq/BasicLinqTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/BasicLinqTests.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Linq/BasicLinqTests.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -0,0 +1,19 @@ +using System.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.Linq +{ + [TestFixture] + public class BasicLinqTests : LinqTestCase + { + [Test] + public void DummySelect() + { + var soldOutProducts = from p in db.Products select p; + + var results = soldOutProducts.ToList(); + + Assert.AreEqual(0, results.Count); + } + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate.Test/Linq/BasicLinqTests.cs ___________________________________________________________________ Added: svn:executable + * Added: trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Address.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Address.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Address.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -0,0 +1,117 @@ +namespace NHibernate.Test.Linq.Entities +{ + public class Address + { + private readonly string _city; + private readonly string _country; + private readonly string _fax; + private readonly string _phoneNumber; + private readonly string _postalCode; + private readonly string _region; + private readonly string _street; + + public Address() : this(null, null, null, null, null, null, null) + { + } + + public Address(string street, string city, string region, string postalCode, + string country, string phoneNumber, string fax) + { + _street = street; + _city = city; + _region = region; + _postalCode = postalCode; + _country = country; + _phoneNumber = phoneNumber; + _fax = fax; + } + + public string Street + { + get { return _street; } + } + + public string City + { + get { return _city; } + } + + public string Region + { + get { return _region; } + } + + public string PostalCode + { + get { return _postalCode; } + } + + public string Country + { + get { return _country; } + } + + public string PhoneNumber + { + get { return _phoneNumber; } + } + + public string Fax + { + get { return _fax; } + } + + public static bool operator ==(Address address1, Address address2) + { + if (!ReferenceEquals(address1, null) && + ReferenceEquals(address2, null)) + { + return false; + } + + if (ReferenceEquals(address1, null) && + !ReferenceEquals(address2, null)) + { + return false; + } + + return address1.Equals(address2); + } + + public static bool operator !=(Address address1, Address address2) + { + return !(address1 == address2); + } + + public override bool Equals(object obj) + { + var address = obj as Address; + + if (address != null) + { + return + _street == address.Street && + _city == address.City && + _region == address.Region && + _postalCode == address.PostalCode && + _country == address.Country && + _phoneNumber == address.PhoneNumber && + _fax == address.Fax; + } + + return base.Equals(obj); + } + + public override int GetHashCode() + { + return + (_street ?? string.Empty).GetHashCode() ^ + (_city ?? string.Empty).GetHashCode() ^ + (_region ?? string.Empty).GetHashCode() ^ + (_postalCode ?? string.Empty).GetHashCode() ^ + (_country ?? string.Empty).GetHashCode() ^ + (_phoneNumber ?? string.Empty).GetHashCode() ^ + (_fax ?? string.Empty).GetHashCode(); + } + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Address.cs ___________________________________________________________________ Added: svn:executable + * Added: trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Customer.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Customer.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Customer.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -0,0 +1,73 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Iesi.Collections.Generic; + +namespace NHibernate.Test.Linq.Entities +{ + public class Customer : Entity<Customer> + { + private readonly ISet<Order> _orders; + private Address _address; + private string _companyName; + private string _contactName; + private string _contactTitle; + + public Customer() : this(null) + { + } + + public Customer(string companyName) + { + _orders = new HashedSet<Order>(); + + _companyName = companyName; + } + + public virtual string CompanyName + { + get { return _companyName; } + set { _companyName = value; } + } + + public virtual string ContactName + { + get { return _contactName; } + set { _contactName = value; } + } + + public virtual string ContactTitle + { + get { return _contactTitle; } + set { _contactTitle = value; } + } + + public virtual Address Address + { + get { return _address; } + set { _address = value; } + } + + public virtual ReadOnlyCollection<Order> Orders + { + get { return new ReadOnlyCollection<Order>(new List<Order>(_orders)); } + } + + public virtual void AddOrder(Order order) + { + if (!_orders.Contains(order)) + { + _orders.Add(order); + order.Customer = this; + } + } + + public virtual void RemoveOrder(Order order) + { + if (_orders.Contains(order)) + { + _orders.Remove(order); + order.Customer = null; + } + } + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Customer.cs ___________________________________________________________________ Added: svn:executable + * Added: trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Employee.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Employee.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Employee.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Iesi.Collections.Generic; + +namespace NHibernate.Test.Linq.Entities +{ + public class Employee : Entity<Employee> + { + private readonly ISet<Order> _orders; + private readonly ISet<Employee> _subordinates; + private readonly IList<Territory> _territories; + private Address _address; + private DateTime? _birthDate; + private string _extension; + private string _firstName; + private DateTime? _hireDate; + private string _lastName; + private string _notes; + private Employee _superior; + private string _title; + private string _titleOfCourtesy; + + public Employee() + : this(null, null) + { + } + + public Employee(string firstName, string lastName) + { + _firstName = firstName; + _lastName = lastName; + + _subordinates = new HashedSet<Employee>(); + _orders = new HashedSet<Order>(); + _territories = new List<Territory>(); + } + + public virtual string FirstName + { + get { return _firstName; } + set { _firstName = value; } + } + + public virtual string LastName + { + get { return _lastName; } + set { _lastName = value; } + } + + public virtual string Title + { + get { return _title; } + set { _title = value; } + } + + public virtual string TitleOfCourtesy + { + get { return _titleOfCourtesy; } + set { _titleOfCourtesy = value; } + } + + public virtual DateTime? BirthDate + { + get { return _birthDate; } + set { _birthDate = value; } + } + + public virtual DateTime? HireDate + { + get { return _hireDate; } + set { _hireDate = value; } + } + + public virtual Address Address + { + get { return _address; } + set { _address = value; } + } + + public virtual string Extension + { + get { return _extension; } + set { _extension = value; } + } + + public virtual string Notes + { + get { return _notes; } + set { _notes = value; } + } + + public virtual Employee Superior + { + get { return _superior; } + set { _superior = value; } + } + + public virtual ReadOnlyCollection<Employee> Subordinates + { + get { return new ReadOnlyCollection<Employee>(new List<Employee>(_subordinates)); } + } + + public virtual ReadOnlyCollection<Territory> Territories + { + get { return new ReadOnlyCollection<Territory>(_territories); } + } + + public virtual ReadOnlyCollection<Order> Orders + { + get { return new ReadOnlyCollection<Order>(new List<Order>(_orders)); } + } + + public virtual void AddSubordinate(Employee subordinate) + { + if (!_subordinates.Contains(subordinate)) + { + subordinate.Superior = this; + _subordinates.Add(subordinate); + } + } + + public virtual void RemoveSubordinate(Employee subordinate) + { + if (_subordinates.Contains(subordinate)) + { + subordinate.Superior = null; + _subordinates.Remove(subordinate); + } + } + + public virtual void AddOrder(Order order) + { + if (!_orders.Contains(order)) + { + order.Employee = this; + _orders.Add(order); + } + } + + public virtual void RemoveOrder(Order order) + { + if (_orders.Contains(order)) + { + order.Employee = null; + _orders.Remove(order); + } + } + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Employee.cs ___________________________________________________________________ Added: svn:executable + * Added: trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Entity.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Entity.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Entity.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -0,0 +1,9 @@ +namespace NHibernate.Test.Linq.Entities +{ + public abstract class Entity<T> + { + private long _id = -1; + + public virtual long Id { get { return _id; } set { _id = value; }} + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Entity.cs ___________________________________________________________________ Added: svn:executable + * Added: trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Northwind.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Northwind.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Northwind.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -0,0 +1,40 @@ +using System.Linq; +using NHibernate.Linq; + +namespace NHibernate.Test.Linq.Entities +{ + public class Northwind + { + private readonly ISession _session; + + public Northwind(ISession session) + { + _session = session; + } + + public IQueryable<Customer> Customers + { + get { return _session.Query<Customer>(); } + } + + public IQueryable<Product> Products + { + get { return _session.Query<Product>(); } + } + + public IQueryable<Order> Orders + { + get { return _session.Query<Order>(); } + } + + public IQueryable<OrderLine> OrderLines + { + get { return _session.Query<OrderLine>(); } + } + + public IQueryable<Employee> Employees + { + get { return _session.Query<Employee>(); } + } + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Northwind.cs ___________________________________________________________________ Added: svn:executable + * Added: trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Order.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Order.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Order.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Iesi.Collections.Generic; + +namespace NHibernate.Test.Linq.Entities +{ + public class Order : Entity<Order> + { + private readonly ISet<OrderLine> _orderLines; + private Customer _customer; + private Employee _employee; + private decimal? _freight; + private DateTime? _orderDate; + private DateTime? _requiredDate; + private string _shippedTo; + private Shipper _shipper; + private Address _shippingAddress; + private DateTime? _shippingDate; + + public Order() : this(null) + { + } + + public Order(Customer customer) + { + _orderLines = new HashedSet<OrderLine>(); + + _customer = customer; + } + + public virtual Customer Customer + { + get { return _customer; } + set { _customer = value; } + } + + public virtual Employee Employee + { + get { return _employee; } + set { _employee = value; } + } + + public virtual DateTime? OrderDate + { + get { return _orderDate; } + set { _orderDate = value; } + } + + public virtual DateTime? RequiredDate + { + get { return _requiredDate; } + set { _requiredDate = value; } + } + + public virtual DateTime? ShippingDate + { + get { return _shippingDate; } + set { _shippingDate = value; } + } + + public virtual Shipper Shipper + { + get { return _shipper; } + set { _shipper = value; } + } + + public virtual decimal? Freight + { + get { return _freight; } + set { _freight = value; } + } + + public virtual string ShippedTo + { + get { return _shippedTo; } + set { _shippedTo = value; } + } + + public virtual Address ShippingAddress + { + get { return _shippingAddress; } + set { _shippingAddress = value; } + } + + public virtual ReadOnlyCollection<OrderLine> OrderLines + { + get { return new ReadOnlyCollection<OrderLine>(new List<OrderLine>(_orderLines)); } + } + + public virtual void AddOrderLine(OrderLine orderLine) + { + if (!_orderLines.Contains(orderLine)) + { + orderLine.Order = this; + _orderLines.Add(orderLine); + } + } + + public virtual void RemoveOrderLine(OrderLine orderLine) + { + if (_orderLines.Contains(orderLine)) + { + _orderLines.Remove(orderLine); + orderLine.Order = null; + } + } + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Order.cs ___________________________________________________________________ Added: svn:executable + * Added: trunk/nhibernate/src/NHibernate.Test/Linq/Entities/OrderLine.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/Entities/OrderLine.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Linq/Entities/OrderLine.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -0,0 +1,51 @@ +namespace NHibernate.Test.Linq.Entities +{ + public class OrderLine : Entity<OrderLine> + { + private decimal _discount; + private Order _order; + private Product _product; + private int _quantity; + private decimal _unitPrice; + + public OrderLine() : this(null, null) + { + } + + public OrderLine(Order order, Product product) + { + _order = order; + _product = product; + } + + public virtual Order Order + { + get { return _order; } + set { _order = value; } + } + + public virtual Product Product + { + get { return _product; } + set { _product = value; } + } + + public virtual decimal UnitPrice + { + get { return _unitPrice; } + set { _unitPrice = value; } + } + + public virtual int Quantity + { + get { return _quantity; } + set { _quantity = value; } + } + + public virtual decimal Discount + { + get { return _discount; } + set { _discount = value; } + } + } +} \ No newline at end of file Property changes on: trunk/nhibernate/src/NHibernate.Test/Linq/Entities/OrderLine.cs ___________________________________________________________________ Added: svn:executable + * Added: trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Product.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Product.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/Linq/Entities/Product.cs 2009-08-13 11:56:42 UTC (rev 4689) @@ -0,0 +1,89 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace NHibernate.Test.Linq.Entities +{ + public class Product : Entity<Product> + { + private readonly IList<OrderLine> _orderLines; + private ProductCategory _category; + private bool _discontinued; + private string _name; + private string _quantityPerUnit; + private int _reorderLevel; + private Supplier _supplier; + private decimal? _unitPrice; + private int _unitsInStock; + private int _unitsOnOrder; + + public Product() : this(null) + { + } + + public Product(string name) + { + _orderLines = new List<OrderLine>(); + + _name = name; + } + + public virtual string Name + { + get { return _name; } + set { _name = value; } + } + + public virtual Supplier Supplier + { + get { return _supplier; } + set { _supplier = value; } + } + + public virtual ProductCategory Category + { + get { return _category; } + set { _category = value; } + } + + public virtual string QuantityPerUnit + { + get { return _quantityPerUnit; } + set { _quantityPerUnit = value; } + } + + public virtual decimal? UnitPrice + { + get { return _unitPrice; } + set { _unitPrice = value; } + } + + public virtual int UnitsInStock + { + get { return _unitsInSt... [truncated message content] |