Есть ли способ получить fluent-nhibernate для сравнения значения ValueObject со строкой, используя QueryOver? - PullRequest
0 голосов
/ 02 мая 2019

Следуя некоторым курсам Владимира Хорикова по DDD, я абстрагировал некоторые свойства примитивного класса в ValueObjects. Например, свойство Username моего объекта Account представляло собой строку, но для проверки его в качестве концепции домена я создал тип Username.

Это привело к прекращению работы QueryOver, см. Код.

Я получаю исключение: NHibernate.QueryException: 'could not resolve property: Username.Value of: PtPro.Domain.Account.Account'

// Account.cs
public class Account : AggregateRoot
    {
        private string _username;
        public virtual Username Username
        {
            get => (Username)_username;
            set => _username = value;
        }
    } // Rest of class removed for brevity

// AccountMap.cs
    public class AccountMap : ClassMap<Account>
    {
        public AccountMap()
        {
            Id(x => x.Id);

            Map(x => x.Username).CustomType<string>().Access.CamelCaseField(Prefix.Underscore);

            References(Reveal.Member<Account, Client>("Client"))
                .Cascade
                .SaveUpdate();
        }
    } // Rest of class removed

// AccountRepository.cs
        public Account GetWithClientByUsername(string username)
        {
            Account ac = null;
            Client cl = null;
            var account =  _session.QueryOver<Account>(() => ac)
                .JoinAlias(() => ac.Client, () => cl)
                .Where(() => ac.Username.Value == username)
                .SingleOrDefault<Account>();
            return account;
        }

// Username.cs
    public class Username : ValueObject<Username>
    {
        public string Value { get; }

        private Username() { }

        private Username(string value)
        {
            Value = value;
        }

        public static Result<Username> Create(string username)
        {
            username = (username ?? string.Empty).Trim();

            if (username.Length == 0)
                return Result.Fail<Username>("Username is invalid");

            return Result.Ok(new Username(username));
        }

        public static implicit operator string(Username username)
        {
            return username.Value;
        }

        public static explicit operator Username(string username)
        {
            return Create(username).Value;
        }

        protected override bool EqualsCore(Username other)
        {
            return other.Value.Equals(Value);
        }

        protected override int GetHashCodeCore()
        {
            return Value.GetHashCode();
        }
    }

Ответы [ 2 ]

1 голос
/ 06 мая 2019

Объекты запросов NHibernate плохо поддерживают объекты-значения.Вместо этого попробуйте hql, он выполняет такие отображения.

string query = @"
    from Account a inner join fetch a.Client c
    where a.Username = :userName";

IList<Subscription> subscriptions = _session.CreateQuery(query)
    .SetParameter("userName", username)
    .List<Subscription>();

Дополнительная информация: https://nhibernate.info/doc/nhibernate-reference/queryhql.html

0 голосов
/ 03 мая 2019

Кажется, отображение компонентов хорошо подходит для таких объектов значений.

public class UsernameMap : ComponentMap<Username>
{
    public UsernameMap()
    {
        Map(x => x.Value).Access.CamelCaseField(Prefix.Underscore);
    }
}

public class AccountMap : ClassMap<Account>
{
    public AccountMap()
    {
        //Use Component instead of Map for all Username mappings
        Component(x => x.Username);
    }
}
...