Query with using paired EntitySets twice (e.g. EntityA.EntitiesB.SelectMany(entityB => entityB.EntitiesA) may return empty set. Look at the example below:

namespace Sample
{
    using System;
    using Xtensive.Orm;
    using Xtensive.Orm.Configuration;
    using System.Linq;
    using Domain = Xtensive.Orm.Domain;

    [HierarchyRoot]
    public class MasterEntity : Entity
    {
        [Key] [Field] public Guid MasterId { get; }

        [Field] public EntitySet<SlaveEntity> Slaves { get; set; }
    }

    [HierarchyRoot]
    public class SlaveEntity : Entity
    {
        [Key] [Field] public Guid SlaveId { get; }

        [Association(PairTo = nameof(MasterEntity.Slaves))]
        [Field] public EntitySet<MasterEntity> Masters { get; set; }
    }

    class Program
    {
        static void Main()
        {
            var dc = new DomainConfiguration("sqlserver", "Data Source=.; Initial Catalog=DO40-Tests;Connection Timeout=300;Integrated Security = true;");
            dc.Types.Register(typeof(Program).Assembly);
            dc.UpgradeMode = DomainUpgradeMode.Recreate;
            var sessionConfiguration = new SessionConfiguration(SessionOptions.AutoActivation | SessionOptions.ServerProfile);

            using (var domain = Domain.Build(dc))
            {
                using (var session = domain.OpenSession(sessionConfiguration))
                using (session.Activate())
                using (session.OpenTransaction())
                {
                    PopulateData();
                    ShowBug();
                }
            }

            Console.ReadKey(true);
        }

        private static void PopulateData()
        {
            var master = new MasterEntity();
            master.Slaves.Add(new SlaveEntity());
        }

        private static void ShowBug()
        {
            var targetMaster = Query.All<MasterEntity>().First();
            var targetSlave = Query.All<SlaveEntity>().First();

            var queryMasters = Query.All<MasterEntity>()
                .Any(o => o.Slaves.SelectMany(t => t.Masters).Contains(targetMaster));
            var inMemoryMasters = Query.All<MasterEntity>().AsEnumerable()
                .Any(o => o.Slaves.SelectMany(t => t.Masters).Contains(targetMaster));

            Console.WriteLine($"Masters: {queryMasters} - {inMemoryMasters}");

            var querySlaves = Query.All<SlaveEntity>()
                .Any(o => o.Masters.SelectMany(t => t.Slaves).Contains(targetSlave));
            var inMemorySlaves = Query.All<SlaveEntity>().AsEnumerable()
                .Any(o => o.Masters.SelectMany(t => t.Slaves).Contains(targetSlave));

            Console.WriteLine($"Slaves: {querySlaves} - {inMemorySlaves}");
        }
    }
}

Query for slaves returns different results for database query and inmemory query:

Masters: True - True
Slaves: False - True

Generated SQL queries contain strange where clause after joins of entity table with entityset tables ([b] refers to table of EntitySet):

For Masters:

([b].[MasterEntity] = [b].[MasterEntity])

For Slaves:

([b].[SlaveEntity] = [b].[MasterEntity])

asked Apr 12 '19 at 10:13

Platonov's gravatar image

Platonov
5778

edited Apr 12 '19 at 10:15


2 Answers:

Hello Platonov,

The bug is confirmed. I have created an issue for that. Something's wrong with SelectMany applied directly to EntitySet as source.

A workaround (in case you need it right now):

var querySlaves = Query.All<slaveentity>()
          .Any(x1 => x1.Masters
                       .Select(m=>m)
                       .SelectMany(t1 => t1.Slaves.Select(s=>s))
                       .Contains(targetSlave));

answered Apr 15 '19 at 07:07

Alexey%20Kulakov's gravatar image

Alexey Kulakov
77225

Thanks for your answer and fast workaround!

answered Apr 15 '19 at 07:47

Platonov's gravatar image

Platonov
5778

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

powered by OSQA