Hi
- 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)
- Strange bug with translating LINQ to SQL. SQL throw exception: duplicated column names (TestDuplicatedNames)
- 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'.'
Hello Anton. Could you please add relevant model parts as well as your compiler methods?
Added Facepalm