Hi

  1. Recursive virtual fields. When expression return property that call this expression obviously StackOverflowException, but maybe you can handle it on compile time validation? (TestStackOverflow - test in project)
  2. Strange bug with translating LINQ to SQL. SQL throw exception: duplicated column names (TestDuplicatedNames)
  3. Join two sequence on nullable fields. When both fields NULL, row doesn't add to result, in SQL it's normal behavior, but with objects maybe not(TestNullableCompare)

Tests

    namespace Project1
    {
        using System.Linq;
        using Microsoft.VisualStudio.TestTools.UnitTesting;
        using Project1.Model;
        using Xtensive.Core;
        using Xtensive.Orm;
        using Xtensive.Orm.Configuration;

        [TestClass]
        public class TestEntities
        {
            protected Domain domain;
            protected Session session;
            protected TransactionScope transactionScope;

            [TestInitialize()]
            public virtual void Initialize()
            {
                var config = new DomainConfiguration
                                 {
                                     ConnectionInfo = new ConnectionInfo("sqlserver://localhost/DO40-Tests")
                                 };

                config.Types.Register(this.GetType().Assembly);
                config.Name = "Default";
                config.UpgradeMode = UpgradeMode;
                domain = Domain.Build(config);
                CreateBase();
                OpenTransactions();
            }
            protected virtual void CreateBase()
            {
                if (this.domain.Configuration.UpgradeMode != DomainUpgradeMode.Recreate)
                {
                    return;
                }

                using (var baseSession = this.domain.OpenSession())
                {
                    using (baseSession.Activate())
                    using (var baseTransactionScope = baseSession.OpenTransaction())
                    {
                        var somePlace = new Place() { Name = "SomePlace" };
                        var otherPlace = new Place() { Name = "OtherPlace" };

                        var leader1 = new Man() { Name = "Company leader 1" };
                        var leader2 = new Man() { Name = "Company leader 2" };
                        var slave1 = new Man() { Name = "Slave 1" };
                        var slave2 = new Man() { Name = "Slave 2" };

                        var company1 = new Company() { Name = "Company 1", CompanyOwner = leader1, Place = somePlace };
                        var company2 = new Company() { Name = "Company 2", CompanyOwner = leader2 };

                        var realUnit = new Unit()
                                           {
                                               Company = company1,
                                               Name = "Real unit",
                                               VirtualMan = false,
                                               DefaultMan = slave1
                                           };
                        var virtualUnit = new Unit()
                                              {
                                                  Company = company1,
                                                  Name = "Virtual unit",
                                                  VirtualMan = true,
                                                  DefaultMan = slave2
                                              };

                        var warning = new WarningLevel() { Name = "Предупреждение" };
                        var error = new WarningLevel() { Name = "Ошибка" };

                        new SomeEvent()
                            {
                                Company = company1,
                                Unit = realUnit,
                                Man = slave1,
                                WarningLevel = warning,
                                Year = 2012,
                                Month = 11,
                                AverageScore = 10,
                                AverageThreat = 2
                            };

                        new SomeEvent()
                            {
                                Company = company1,
                                Place = somePlace,
                                Unit = realUnit,
                                Man = slave1,
                                WarningLevel = warning,
                                Year = 2012,
                                Month = 11,
                                AverageScore = 10,
                                AverageThreat = 2
                            };

                        baseTransactionScope.Complete();
                    }
                }
            }

            protected virtual void OpenTransactions()
            {
                session = domain.OpenSession();
                transactionScope = session.OpenTransaction();
            }

            [TestCleanup()]
            public void Cleanup()
            {
                CloseTransactions();
            }
            protected virtual void CloseTransactions()
            {
                transactionScope.Dispose();
                session.Dispose();
            }
            protected virtual DomainUpgradeMode UpgradeMode
            {
                get{return DomainUpgradeMode.Recreate; }
            }

            [TestMethod]
            public void TestStackOverflow()
            {
                session.Query.All<Unit>().Select(u => u.Man).ToList();
            }

            [TestMethod]
            public void TestDuplicatedNames()
            {
               (from e in session.Query.All<TestEntity2>()
                           group e by new { e.System, e.TestEntity.VirtualSystem }
                               into grp
                               select
                                   new { Sum1 = grp.Sum(i => i.Dec1), Sum2 = grp.Sum(i => i.Dec1), Sum3 = grp.Sum(i => i.Dec1) }).ToList();

            }

            [TestMethod]
            public void TestNullableCompare()
            {
                var res =
                    session.Query.All<Company>().Join(session.Query.All<SomeEvent>(), c => c.Place, e => e.Place, (company, @event) => new {company, @event}).ToList();

                Assert.AreEqual(2, res.Count);
            }
        }
    }

Model:

namespace Project1.Model
{
    using System;
    using System.Linq.Expressions;

    using Xtensive.Core;
    using Xtensive.Linq;
    using Xtensive.Orm;

    /// <summary>
    /// Место события
    /// </summary>
    [HierarchyRoot]
    [Serializable]
    public class Place : Entity
    {
        [Field, Key]
        public int Id { get; private set; }

        /// <summary>
        /// Наименование
        /// </summary>
        [Field]
        public string Name { get; set; }
    }

    /// <summary>
    /// Компания
    /// </summary>
    [HierarchyRoot]
    [Serializable]
    public class Company : Entity
    {
        [Field, Key]
        public int Id { get; private set; }

        /// <summary>
        /// Наименование
        /// </summary>
        [Field]
        public string Name { get; set; }

        /// <summary>
        /// Владелец
        /// </summary>
        [Field(Nullable = false)]
        public Man CompanyOwner { get; set; }

        /// <summary>
        /// Место
        /// </summary>
        [Field]
        public Place Place { get; set; }
    }

    /// <summary>
    /// Человек
    /// </summary>
    [HierarchyRoot]
    [Serializable]
    public class Man : Entity
    {
        [Field, Key]
        public int Id { get; private set; }

        /// <summary>
        /// Наименование
        /// </summary>
        [Field]
        public string Name { get; set; }
    }

    /// <summary>
    /// Исполнитель
    /// </summary>
    [HierarchyRoot]
    [Serializable]
    public class Unit : Entity
    {
        /// <summary>Выражение для Человек </summary>
        private static readonly Expression<Func<Unit, Man>> ManExpression =
            obj => obj.VirtualMan ? obj.Company.CompanyOwner : obj.Man;

        [Field, Key]
        public int Id { get; private set; }

        /// <summary>
        /// Наименование
        /// </summary>
        [Field]
        public string Name { get; set; }

        /// <summary>
        /// Компания
        /// </summary>
        [Field]
        public Company Company { get; set; }

        /// <summary>
        /// Человек на всякий случай
        /// </summary>
        [Field]
        public Man DefaultMan { get; set; }

        /// <summary>
        /// Наименование
        /// </summary>
        [Field]
        public bool VirtualMan { get; set; }

        /// <summary>
        /// Человек
        /// </summary>
        public Man Man
        {
            get
            {
                return ManExpressionCompiled(this);
            }
        }

        private static readonly Func<Unit, Man> ManExpressionCompiled = ManExpression.Compile();

        [CompilerContainer(typeof(Expression))]
        public static class CustomLinqCompilerContainer
        {
            [Compiler(typeof(Unit), "Man", TargetKind.PropertyGet)]
            public static Expression Depositary(Expression assignmentExpression)
            {
                return ManExpression.BindParameters(assignmentExpression);
            }
        }
    }

    /// <summary>
    /// Уровень угрозы
    /// </summary>
    [HierarchyRoot]
    [Serializable]
    public class WarningLevel : Entity
    {
        [Field, Key]
        public int Id { get; private set; }

        /// <summary>
        /// Наименование
        /// </summary>
        [Field]
        public string Name { get; set; }
    }

    /// <summary>
    /// Тестовая сущность0
    /// </summary>
    [HierarchyRoot]
    [Serializable]
    public class SomeEvent : Entity
    {
        [Field, Key]
        public int Id { get; private set; }

        /// <summary>
        /// Место
        /// </summary>
        [Field]
        public Place Place { get; set; }

        /// <summary>
        /// Год
        /// </summary>
        [Field]
        public int Year { get; set; }

        /// <summary>
        /// Месяц
        /// </summary>
        [Field]
        public int Month { get; set; }

        /// <summary>
        /// Компания
        /// </summary>
        [Field]
        public Company Company { get; set; }

        /// <summary>
        /// Исполнитель
        /// </summary>
        [Field]
        public Unit Unit { get; set; }

        /// <summary>
        /// Человек
        /// </summary>
        [Field]
        public Man Man { get; set; }

        /// <summary>
        /// Уровень угрозы
        /// </summary>
        [Field]
        public WarningLevel WarningLevel { get; set; }

        /// <summary>
        /// Очки
        /// </summary>
        [Field]
        public decimal AverageScore { get; set; }

        /// <summary>
        /// Угроза
        /// </summary>
        [Field]
        public decimal AverageThreat { get; set; }
    }

    /// <summary>
    /// Тестовая сущность0
    /// </summary>
    [HierarchyRoot]
    [Serializable]
    public class TestEntity0 : Entity
    {
        [Field, Key]
        public int Id { get; private set; }

        /// <summary>
        /// Наименование
        /// </summary>
        [Field]
        public TestEntity1 Entity1 { get; set; }
    }

    /// <summary>
    /// Тестовая сущность1
    /// </summary>
    [HierarchyRoot]
    [Serializable]
    public class TestEntity1 : Entity
    {
        [Field, Key]
        public int Id { get; private set; }
    }

    /// <summary>
    /// Тестовая сущность
    /// </summary>
    [HierarchyRoot]
    [Serializable]
    public class TestEntity : Entity
    {
        [Field, Key]
        public int Id { get; private set; }

        private static readonly Expression<Func<TestEntity, TestEntity1>> SystemExpression =
            obj => obj.ForVirtual ? obj.System : obj.Service.Entity1;

        /// <summary>
        /// Наименование
        /// </summary>
        [Field]
        public string Name { get; set; }

        /// <summary>
        /// Для виртуального
        /// </summary>
        [Field]
        public bool ForVirtual { get; set; }

        /// <summary>
        /// Сервис
        /// </summary>
        [Field]
        public TestEntity0 Service { get; set; }

        /// <summary>
        /// Система
        /// </summary>
        [Field]
        public TestEntity1 System { get; set; }

        /// <summary>
        /// Система
        /// </summary>
        public TestEntity1 VirtualSystem
        {
            get { return SystemExpressionCompiled(this); }
        }

        private static readonly Func<TestEntity, TestEntity1> SystemExpressionCompiled =
    SystemExpression.Compile();

        [CompilerContainer(typeof(Expression))]
        public static class CustomLinqCompilerContainer
        {
            [Compiler(typeof(TestEntity), "VirtualSystem", TargetKind.PropertyGet)]
            public static Expression Depositary(Expression assignmentExpression)
            {
                return SystemExpression.BindParameters(assignmentExpression);
            }
        }
    }

    /// <summary>
    /// Тестовая сущность2
    /// </summary>
    [HierarchyRoot]
    [Serializable]
    public class TestEntity2 : Entity
    {
        [Field, Key]
        public int Id { get; private set; }

        /// <summary>
        /// Сервис
        /// </summary>
        [Field]
        public TestEntity TestEntity { get; set; }

        /// <summary>
        /// Система
        /// </summary>
        [Field]
        public TestEntity1 System { get; set; }

        /// <summary>
        /// Число 1
        /// </summary>
        [Field]
        public decimal Dec1 { get; set; }

        /// <summary>
        /// Число 2
        /// </summary>
        [Field]
        public decimal Dec2 { get; set; }

        /// <summary>
        /// Число 3
        /// </summary>
        [Field]
        public decimal Dec3 { get; set; }
    }
}

29.01.2013 Second test with DO 4.6.2

Exception:

SQL error occured.

SQL error details 'Type: Unknown;'

Query 'SELECT (SELECT SUM([a].[Dec1]) FROM [dbo].[TestEntity2] [a] LEFT OUTER JOIN [dbo].[TestEntity] [b] ON ([a].[TestEntity.Id] = [b].[Id]) LEFT OUTER JOIN [dbo].[TestEntity0] [c] ON ([b].[Service.Id] = [c].[Id]) WHERE (([a].[System.Id] = [d].[System.Id]) AND ([b].[ForVirtual] = [d].[ForVirtual]) AND ([b].[System.Id] = [d].[System.Id]) AND ([c].[Entity1.Id] = [d].[Entity1.Id]))) AS [c01umn], (SELECT SUM([e].[Dec1]) FROM [dbo].[TestEntity2] [e] LEFT OUTER JOIN [dbo].[TestEntity] [f] ON ([e].[TestEntity.Id] = [f].[Id]) LEFT OUTER JOIN [dbo].[TestEntity0] [g] ON ([f].[Service.Id] = [g].[Id]) WHERE (([e].[System.Id] = [d].[System.Id]) AND ([f].[ForVirtual] = [d].[ForVirtual]) AND ([f].[System.Id] = [d].[System.Id]) AND ([g].[Entity1.Id] = [d].[Entity1.Id]))) AS [c01umn1], (SELECT SUM([h].[Dec1]) FROM [dbo].[TestEntity2] [h] LEFT OUTER JOIN [dbo].[TestEntity] [i] ON ([h].[TestEntity.Id] = [i].[Id]) LEFT OUTER JOIN [dbo].[TestEntity0] [j] ON ([i].[Service.Id] = [j].[Id]) WHERE (([h].[System.Id] = [d].[System.Id]) AND ([i].[ForVirtual] = [d].[ForVirtual]) AND ([i].[System.Id] = [d].[System.Id]) AND ([j].[Entity1.Id] = [d].[Entity1.Id]))) AS [c01umn2] FROM (SELECT [k].[System.Id], [l].[ForVirtual], [l].[System.Id], [m].[Entity1.Id] FROM [dbo].[TestEntity2] [k] LEFT OUTER JOIN [dbo].[TestEntity] [l] ON ([k].[TestEntity.Id] = [l].[Id]) LEFT OUTER JOIN [dbo].[TestEntity0] [m] ON ([l].[Service.Id] = [m].[Id]) GROUP BY [k].[System.Id], [l].[ForVirtual], [l].[System.Id], [m].[Entity1.Id]) [d] LEFT OUTER JOIN [dbo].[TestEntity1] [n] ON ([d].[System.Id] = [n].[Id]) LEFT OUTER JOIN [dbo].[TestEntity1] [o] ON ([d].[System.Id] = [o].[Id]) LEFT OUTER JOIN [dbo].[TestEntity1] [p] ON ([d].[Entity1.Id] = [p].[Id]);'

Original message 'The column 'System.Id' was specified multiple times for 'd'.'

asked Nov 23 '12 at 07:08

Anton%20Guschin's gravatar image

Anton Guschin
73303035

edited Jan 29 '13 at 02:43

Hello Anton. Could you please add relevant model parts as well as your compiler methods?

(Nov 28 '12 at 05:25) Denis Krjuchkov Denis%20Krjuchkov's gravatar image

Added Facepalm

(Nov 29 '12 at 07:40) Anton Guschin Anton%20Guschin's gravatar image

2 Answers:

Hello Anton,

  1. We'll consider detecting this situation when executing such queries
  2. Confirmed and fixed
  3. It's impractical to avoid SQL behavior from performance standpoint. You can however write desired query manually:

    var res =
      session.Query.All<Company>()
             .Join(session.Query.All<SomeEvent>(),
                   c => c.Place != null ? c.Place.Id : -1,
                   e => e.Place != null ? e.Place.Id : -1,
                   (company, @event) => new {company, @event})
             .ToList();
    

answered Dec 05 '12 at 08:47

Denis%20Krjuchkov's gravatar image

Denis Krjuchkov
179325

DO 4.6.2 Second test not passed Modify general message

(Jan 29 '13 at 02:50) Anton Guschin Anton%20Guschin's gravatar image

4.6.2 does not contain the fix. It would be included in 4.6.3 which is expected on this week.

(Jan 29 '13 at 04:00) Denis Krjuchkov Denis%20Krjuchkov's gravatar image

Yeah. Works with 4.6.3

(Feb 21 '13 at 00:12) Anton Guschin Anton%20Guschin's gravatar image

Thanks a lot

answered Jan 15 '13 at 06:38

Anton%20Guschin's gravatar image

Anton Guschin
73303035

Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!
toggle preview

Subscription:

Once you sign in you will be able to subscribe for any updates here

Tags:

×574
×71
×57

Asked: Nov 23 '12 at 07:08

Seen: 9,147 times

Last updated: Feb 21 '13 at 00:12

powered by OSQA