Выполнение запросов по нескольким объектам

#c# #nhibernate #nhibernate-criteria

#c# #nhibernate #nhibernate-критерии

Вопрос:

У меня есть странное требование, которое я не уверен, как решить.

Предполагая следующее определение класса:

 public class Client
{
    public Guid Id { get; set; }
    public String Person { get; set; }
    public IList<Client> SecondaryClients { get; set; }
    public Client PrimaryClient { get; set; }
} 

public class Person
{
    public Guid Id { get; set; }
    public String Name { get; set; }
}
 

Когда пользователь ищет в системе клиента по имени, ему необходимо выполнить поиск по всем основным клиентам, а также вторичным клиентам, которые находятся на расстоянии одного перехода. (т.е. если PrimaryClient установлен, нам нужно проверить PrimaryClient .Человек.Имя свойства, однако нам не нужно беспокоиться о PrimaryClient .PrimaryClient.)

Используя DetachedCriteria, у меня есть следующее:

 var clientQuery = DetachedCriteria.For<Client>();
            clientQuery.Add(Restrictions.Disjunction()
                                .Add(Restrictions.Like("Person.Surname", lastName, MatchMode.Start))
                                .Add(Restrictions.Like("PrimaryClient.Person.Surname", lastName, MatchMode.Start))
                                .Add(Restrictions.Like("SecondaryClients.Person.Surname", lastName, MatchMode.Start)));
            var session = OpenSession();
            session.BeginTransaction();
            var clients = clientQuery.GetExecutableCriteria(session).Future<Client>();
            session.Transaction.Commit();
            session.Close();
 

Очевидно, что это далеко не так. Покопавшись, я обнаружил, что мне нужно настроить псевдонимы. В первом случае было легко найти человека.Фамилия:

 var clientQuery = DetachedCriteria.For<Client>();
        clientQuery = clientQuery.CreateAlias("Person", "p");
        clientQuery.Add(Restrictions.Disjunction()
                            .Add(Restrictions.Like("p.Surname", lastName, MatchMode.Start))
                            .Add(Restrictions.Like("PrimaryClient.Person.Surname", lastName, MatchMode.Start))
                            .Add(Restrictions.Like("SecondaryClients.Person.Surname", lastName, MatchMode.Start)));
        var session = OpenSession();
        session.BeginTransaction();
        var clients = clientQuery.GetExecutableCriteria(session).Future<Client>();
        session.Transaction.Commit();
        session.Close();
 

Однако, насколько я понимаю, я не уверен, что я могу сделать для псевдонима PrimaryClient .Человек. Я иду по неверному пути здесь? Любая помощь будет оценена.

ПРИМЕЧАНИЕ: я забыл упомянуть изначально. Возможно, что SecondaryClients и PrimaryClient имеют значение null.

Комментарии:

1. Я думаю, что дизайн вашего класса не идеален, я имею в виду клиентский класс, который имеет PrimaryClient и имеет некоторые SecondaryClients. мне это кажется немного странным.

2. Я не мог не согласиться. К сожалению, я пришел к проекту в конце цикла разработки и не получил представления о том, как все было спроектировано.

Ответ №1:

Для тех, кто ведет учет, я смог выяснить, как это сделать. Я не уверен, есть ли более эффективный способ, однако вот как я настраиваю запрос с помощью DetachedCriteria.

 var clientQuery = DetachedCriteria.For<Client>("Client");
clientQuery = clientQuery.CreateAlias("Person", "p");

var primaryQuery = DetachedCriteria.For<Client>("Primary");
primaryQuery.SetProjection(Projections.Property("Primary.Id"));
primaryQuery.Add(Restrictions.EqProperty("Client.PrimaryClient", "Primary.Id"));
primaryQuery.CreateAlias("Person", "p");
primaryQuery.Add(Restrictions.Like("p.Surname", lastName, MatchMode.Start));

var secondaryQuery = DetachedCriteria.For<Client>();
secondaryQuery.SetProjection(Projections.Property("Id"));
secondaryQuery.CreateCriteria("SecondaryClients")
              .CreateCriteria("Person")
              .Add(Restrictions.Like("Surname", lastName, MatchMode.Start));

clientQuery.Add(Restrictions.Disjunction()
                    .Add(Restrictions.Like("p.Surname", lastName, MatchMode.Start))
                    .Add(Subqueries.Exists(primaryQuery))
                    .Add(Subqueries.PropertyIn("Id", secondaryQuery)));
 

Ответ №2:

Я думаю, вы можете использовать этот запрос:

 var result = _session.Linq<Client>.Where(client => client.Person.Name.StartsWith(lastName) ||
                                                   client.PrimaryClient.Name.StartsWith(lastName) ||
                                                   client.SecondaryClients.Any(sClient =>  sClient.Person.Name.StartsWith(lastName)));