Hi Atsushi,
in theory, DbLinq should only use its own EntitySet<> and EntityRef<>. If a
non-DbLinq class is present somewhere in test code, this is a mistake.
DbLinq probably still supports in the core a bit of MS EntitySet and Ref to
keep a bit of compatibility, but we may also drop those parts in the future.

Regarding eager loading, nothing appears to be in progress (I haven't heard
from Pablo for a while, by the way). I can develop my architecture idea
about this if you are interested.

Anyway, the following remaining tasks are related and should be solved
together:
- complex subexpressions
- eager and lazy loading (lazy loading currently works, but I'm not sure it
fits in the global idea)

However I haven't been giving DbLinq much time last month (apparently I'm
not the only one), so all of this is in standby mode.

Pascal.

On Thu, Nov 27, 2008 at 10:17, Atsushi Eno <[EMAIL PROTECTED]> wrote:

> Hello,
>
> Now I'm diving into this DataLoadOptions land with a patch.
>
> Basically, the patch adds support for validation of LoadWith() argument
> that should 1) allow only property or field access and 2) reject cyclic
> loading. They are with tests and I think this part is ready to get
> committed. (Note that it does not implement the actual eager loading.)
>
> A problem that I found during this hack was that there are two
> EntitySet<T> and EntityRef<T>: one in DbLinq.Data.Linq and another in
> System.Data.Linq.
>
> To my understanding, this kind of conflicts are usually resolved as
>
>        - DbLinq.Data.Linq.EntitySet<T> in non-strict mode and
>        - System.Data.Linq.EntitySet<T> in strict mode.
>
> But what I've found in running Test_NUnit_MsSql was that
> System.Data.Linq.EntitySet<T> was used in non-strict mode. Hence I had
> to add dirty #if !MONO_STRICT block in DataLoadOptions.cs.
>
> Is this kind of complexity expected? Or is it some kind of bug that
> System.Data.Linq.EntitySet<T> is populated in non-strict mode?
>
> And another question - is there any ongoing effort on eager loading
> i.e. inner join and left join? ;)
>
> Atsushi Eno
>
> >
>
> Index: tests/Test_NUnit/DataLoadOptions_Test.cs
> ===================================================================
> --- tests/Test_NUnit/DataLoadOptions_Test.cs    (revision 0)
> +++ tests/Test_NUnit/DataLoadOptions_Test.cs    (revision 0)
> @@ -0,0 +1,134 @@
> +using System;
> +using System.Collections.Generic;
> +using System.Linq;
> +using System.Text;
> +using NUnit.Framework;
> +using Test_NUnit;
> +
> +#if !MONO_STRICT
> +using nwind;
> +using DbLinq.Data.Linq;
> +#else
> +using MsNorthwind;
> +using System.Data.Linq;
> +#endif
> +
> +#if MONO_STRICT
> +namespace MsNorthwind
> +#else
> +namespace nwind
> +#endif
> +{
> +    public partial class Customer
> +    {
> +        public object ExtraneousMethod()
> +        {
> +            return null;
> +        }
> +    }
> +}
> +
> +#if MYSQL
> +    namespace Test_NUnit_MySql
> +#elif ORACLE
> +#if ODP
> +        namespace Test_NUnit_OracleODP
> +#else
> +        namespace Test_NUnit_Oracle
> +#endif
> +#elif POSTGRES
> +namespace Test_NUnit_PostgreSql
> +#elif SQLITE
> +    namespace Test_NUnit_Sqlite
> +#elif INGRES
> +    namespace Test_NUnit_Ingres
> +#elif MSSQL
> +#if MONO_STRICT
> +namespace Test_NUnit_MsSql_Strict
> +#else
> +    namespace Test_NUnit_MsSql
> +#endif
> +#elif FIREBIRD
> +    namespace Test_NUnit_Firebird
> +#else
> +    #error unknown target
> +#endif
> +{
> +    [TestFixture]
> +    public class DataLoadOptions_Test : TestBase
> +    {
> +        static object ThrowException()
> +        {
> +            throw new ApplicationException();
> +        }
> +
> +        [Test]
> +        [ExpectedException(typeof(InvalidOperationException))]
> +        public void LoadWith_BadExpression1()
> +        {
> +            new DataLoadOptions().LoadWith<Customer>(cc =>
> cc.ExtraneousMethod());
> +        }
> +
> +        [Test]
> +        [ExpectedException(typeof(InvalidOperationException))]
> +        public void LoadWith_BadExpression2()
> +        {
> +            new DataLoadOptions().LoadWith<Customer>(cc => 1);
> +        }
> +
> +        [Test]
> +        [ExpectedException(typeof(InvalidOperationException))]
> +        public void LoadWith_BadExpression3()
> +        {
> +            new DataLoadOptions().LoadWith<Customer>(cc =>
> ThrowException());
> +        }
> +
> +        [Test]
> +        [ExpectedException(typeof(InvalidOperationException))]
> +        public void LoadWith_BadExpression4()
> +        {
> +            new DataLoadOptions().LoadWith<Customer>(cc =>
> cc.Orders.Select(o => o));
> +        }
> +
> +        [Test]
> +        [ExpectedException(typeof(InvalidOperationException))]
> +        public void LoadWith_BadExpression5()
> +        {
> +            new DataLoadOptions().LoadWith<Order> (o =>
> o.Customer.Orders);
> +        }
> +
> +        [Test]
> +        [ExpectedException(typeof(InvalidOperationException))]
> +        public void LoadWith_BadCycles1()
> +        {
> +            var lo = new DataLoadOptions();
> +            lo.LoadWith<Customer>(c => c.Orders);
> +            lo.LoadWith<Order>(o => o.Customer);
> +        }
> +
> +        [Test]
> +        [ExpectedException(typeof(InvalidOperationException))]
> +        public void LoadWith_BadCycles2()
> +        {
> +            var lo = new DataLoadOptions();
> +            lo.LoadWith<Order>(o => o.Customer);
> +            lo.LoadWith<Customer>(c => c.Orders);
> +        }
> +
> +        [Test]
> +        public void LoadWith_Good1()
> +        {
> +            var lo = new DataLoadOptions();
> +            lo.LoadWith<Customer>(c => c.Orders);
> +            lo.LoadWith<Order>(o => o.Employee);
> +        }
> +
> +        [Test]
> +        public void LoadWith_Good2()
> +        {
> +            var lo = new DataLoadOptions();
> +            lo.LoadWith<Order>(o => o.Employee);
> +            lo.LoadWith<Customer>(c => c.Orders);
> +        }
> +    }
> +}
> Index: tests/Test_NUnit/Test_NUnit_MsSql.csproj
> ===================================================================
> --- tests/Test_NUnit/Test_NUnit_MsSql.csproj    (revision 960)
> +++ tests/Test_NUnit/Test_NUnit_MsSql.csproj    (working copy)
> @@ -68,6 +68,7 @@
>     </Compile>
>     <Compile Include="Attach.cs" />
>     <Compile Include="CompositePK_Test.cs" />
> +    <Compile Include="DataLoadOptions_Test.cs" />
>     <Compile Include="ReadTests_AnyCountFirst.cs" />
>     <Compile Include="ReadTests_Conversions.cs" />
>     <Compile Include="ReadTests_DateTimeFunctions.cs" />
> Index: tests/Test_NUnit/ReadTests_EntitySet.cs
> ===================================================================
> --- tests/Test_NUnit/ReadTests_EntitySet.cs     (revision 960)
> +++ tests/Test_NUnit/ReadTests_EntitySet.cs     (working copy)
> @@ -288,8 +288,8 @@
>             db.LoadOptions = loadoptions;
>
>             var customer = db.Customers.First();
> -            Assert.IsFalse(customer.Orders.IsDeferred);
> -            Assert.IsTrue(customer.Orders.HasLoadedOrAssignedValues);
> +            Assert.IsFalse(customer.Orders.IsDeferred, "#1");
> +            Assert.IsTrue(customer.Orders.HasLoadedOrAssignedValues,
> "#2");
>         }
>
>         [Test]
> Index: tests/Test_NUnit/Test_NUnit_MsSql_Strict.csproj
> ===================================================================
> --- tests/Test_NUnit/Test_NUnit_MsSql_Strict.csproj     (revision 960)
> +++ tests/Test_NUnit/Test_NUnit_MsSql_Strict.csproj     (working copy)
> @@ -68,6 +68,7 @@
>     </Compile>
>     <Compile Include="Attach.cs" />
>     <Compile Include="CompositePK_Test.cs" />
> +    <Compile Include="DataLoadOptions_Test.cs" />
>     <Compile Include="ReadTest_Subquery.cs" />
>     <Compile Include="DynamicLinqTest.cs" />
>     <Compile Include="ExecuteCommand_Test.cs" />
> Index: src/DbLinq/Data/Linq/DataLoadOptions.cs
> ===================================================================
> --- src/DbLinq/Data/Linq/DataLoadOptions.cs     (revision 960)
> +++ src/DbLinq/Data/Linq/DataLoadOptions.cs     (working copy)
> @@ -100,10 +100,45 @@
>         {
>             // TODO: ensure we have an EntitySet<>
>             var memberInfo = ReflectionUtility.GetMemberInfo(expression);
> +            if (memberInfo == null)
> +                throw new InvalidOperationException("The argument
> expression must be a property access or a field access where the target
> object is the parameter");
>             if (!eagerLoading.Contains(memberInfo))
> +            {
> +                VerifyMemberAccessCycles(memberInfo);
>                 eagerLoading.Add(memberInfo);
> +            }
>         }
>
> +        private void VerifyMemberAccessCycles(MemberInfo member)
> +        {
> +            var mt = GetMemberEntityType (member);
> +            var d = member.DeclaringType;
> +            foreach (var m in eagerLoading)
> +            {
> +                if (m.DeclaringType == mt && GetMemberEntityType (m) == d)
> +                    throw new InvalidOperationException("Illegal cycles
> are detected in the argument expression among other eager-loading
> expressions");
> +            }
> +        }
> +
> +        private Type GetMemberEntityType(MemberInfo member)
> +        {
> +            var mt = member.GetMemberType();
> +            if (mt.IsGenericType)
> +            {
> +#if !MONO_STRICT
> +                if (mt.GetGenericTypeDefinition() == typeof(EntitySet<>))
> // DbLinq.Data.Linq.EntitySet
> +                    mt = mt.GetGenericArguments()[0];
> +                else if (mt.GetGenericTypeDefinition() ==
> typeof(EntityRef<>)) // DbLinq.Data.Linq.EntityRef
> +                    mt = mt.GetGenericArguments()[0];
> +#endif
> +                if (mt.GetGenericTypeDefinition() ==
> typeof(System.Data.Linq.EntitySet<>))
> +                    mt = mt.GetGenericArguments()[0];
> +                else if (mt.GetGenericTypeDefinition() ==
> typeof(System.Data.Linq.EntityRef<>))
> +                    mt = mt.GetGenericArguments()[0];
> +            }
> +            return mt;
> +        }
> +
>         /// <summary>
>         /// Tells if we do eager or lazy loading
>         /// </summary>
> Index: src/DbLinq/Data/Linq/EntityRef.cs
> ===================================================================
> --- src/DbLinq/Data/Linq/EntityRef.cs   (revision 960)
> +++ src/DbLinq/Data/Linq/EntityRef.cs   (working copy)
> @@ -54,7 +54,6 @@
>             hasLoadedOrAssignedValue = true;
>         }
>
> -        [DbLinqToDo]
>         public EntityRef(IEnumerable<TEntity> source)
>         {
>             this.source = source;
> @@ -64,9 +63,14 @@
>
>         public EntityRef(EntityRef<TEntity> entityRef)
>         {
> -            this.source = null;
> -            this.entity = entityRef.Entity;
> -            hasLoadedOrAssignedValue = true;
> +            this.entity = entityRef.entity;
> +            if (entityRef.entity == null && entityRef.source is
> ICloneable)
> +            {
> +                source =
> (IEnumerable<TEntity>)((ICloneable)entityRef.source).Clone();
> +            }
> +            else
> +                source = null;
> +            hasLoadedOrAssignedValue = entityRef.hasLoadedOrAssignedValue;
>         }
>
>         public TEntity Entity
> Index: src/DbLinq/Util/ReflectionUtility.cs
> ===================================================================
> --- src/DbLinq/Util/ReflectionUtility.cs        (revision 960)
> +++ src/DbLinq/Util/ReflectionUtility.cs        (working copy)
> @@ -66,34 +66,39 @@
>         }
>
>         /// <summary>
> -        /// Extracts a MemberInfo with more or less digging
> +        /// Returns MemberInfo specified in the lambda, optional parameter
> expression constraint.
>         /// </summary>
>         /// <param name="expression"></param>
>         /// <returns></returns>
> -        private static MemberInfo GetMemberInfo(Expression expression)
> +        public static MemberInfo GetMemberInfo(LambdaExpression
> expression)
>         {
> -            switch (expression.NodeType)
> -            {
> -            // the ReflectionUtility Get** methods return the value as a
> object. If the value is a struct, we get a cast,
> -            // that we must unwrap
> -            case ExpressionType.Convert:
> -            case ExpressionType.ConvertChecked:
> -                return
> GetMemberInfo(((UnaryExpression)expression).Operand);
> -            case ExpressionType.MemberAccess:
> -                return ((MemberExpression)expression).Member;
> -            default:
> -                return null;
> -            }
> +            var paramExpr = expression.Parameters.Count == 1 ?
> expression.Parameters[0] : null;
> +            return GetMemberInfo(paramExpr, expression.Body);
>         }
>
>         /// <summary>
> -        /// Returns MemberInfo specified in the lambda
> +        /// Returns MemberInfo specified in the lambda, optional parameter
> expression constraint.
>         /// </summary>
>         /// <param name="lambdaExpression"></param>
>         /// <returns></returns>
> -        public static MemberInfo GetMemberInfo(LambdaExpression
> lambdaExpression)
> +        private static MemberInfo GetMemberInfo(Expression
> optionalParamExpr, Expression expression)
>         {
> -            return GetMemberInfo(lambdaExpression.Body);
> +            switch (expression.NodeType)
> +            {
> +                // the ReflectionUtility Get** methods return the value as
> a object. If the value is a struct, we get a cast,
> +                // that we must unwrap
> +                case ExpressionType.Convert:
> +                case ExpressionType.ConvertChecked:
> +                    return GetMemberInfo(optionalParamExpr,
> ((UnaryExpression)expression).Operand);
> +                case ExpressionType.MemberAccess:
> +                    var me = (MemberExpression)expression;
> +                    if (optionalParamExpr == null || me.Expression ==
> optionalParamExpr)
> +                        return me.Member;
> +                    else
> +                        return null;
> +                default:
> +                    return null;
> +            }
>         }
>
>         /// <summary>
>
>


-- 
Pascal.

jabber/gtalk: [EMAIL PROTECTED]
msn: [EMAIL PROTECTED]

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"DbLinq" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/dblinq?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to