【问题标题】:Create ICriterion by iterating through properties via PropertyInfo for NHibernate session通过 NHibernate 会话的 PropertyInfo 遍历属性来创建 Icriterion
【发布时间】:2017-06-17 07:28:15
【问题描述】:

我有一个客户端模型,它具有许多属性,例如名字、姓氏、地址……

通过 ClientEditViewModel 我可以更改 TextBoxes 中的属性值。

public class ClientEditViewModel : EditableViewModelBase
{
    public int ClientID
    {
        get { return this.currentClient.ClientID; }
        set { this.SetProperty(newValue => this.currentClient.ClientID = newValue, value); }
    }

    public string Title
    {
        get { return this.currentClient.Title; }
        set { this.SetProperty(newValue => this.currentClient.Title = newValue, value); }
    }

    public string FirstName
    {
        get { return this.currentClient.FirstName; }
        set { this.SetProperty(newValue => this.currentClient.FirstName = newValue, value); }
    }

    public string LastName
    {
        get { return this.currentClient.LastName; }
        set { this.SetProperty(newValue => this.currentClient.LastName = newValue, value); }
    }

    ...
}

当用户按下搜索按钮时,我想遍历所有属性。如果属性不为空或 null,我想将它们添加到带有“LIKE”限制的查询中。我不想手动检查每个属性,而是想通过反射迭代所有属性。

public ICriterion GetSearchClientCriteria()
{
    var conjunction = Restrictions.Conjunction();

    if (this.ClientID != 0)
    {
        conjunction.Add(Restrictions.Where<Client>(x => x.ClientID == this.ClientID));
        return conjunction;
    }

    foreach (PropertyInfo propertyInfo in this.PropertyInfosWithPublicGetterAndSetter)
    {
        if (propertyInfo.PropertyType == typeof(string))
        {
            string currentPropertyValue = propertyInfo.GetValue(this) as string;

            if (!string.IsNullOrEmpty(currentPropertyValue))
            {
                /* This statement can be executed */
                // conjunction.Add(Restrictions.Where<Client>(c => c.FirstName.IsLike(this.FirstName, MatchMode.Anywhere)));
                conjunction.Add(Restrictions.Where<Client>(c => c.GetType().GetProperty(propertyInfo.Name).GetValue(c, null).ToString()
                .IsLike(this.GetType().GetProperty(propertyInfo.Name).GetValue(this).ToString())));

                return conjunction;
            }
        }
    }

    return conjunction;
}

不幸的是,当我在下面的代码中使用这个连词时,我得到了一个错误。如何在不手动检查每个属性的情况下遍历所有属性?

public class NHibernateRepository : IRepository
{
    public ICollection<T> GetByCriteria<T>(ICriterion criterion) where T : class
    {
        using (var session = this.sessionManager.OpenSession())
        {
            return session.QueryOver<T>().Where(criterion).List();
        }
    }
}

System.InvalidOperationException: Auf die Variable "c" vom Typ "Rechnungsprogramm.Model.Client" wird vom Bereich "" verwiesen, sie ist jedoch 无定义。

System.InvalidOperationException:变量“c” 引用的“Rechnungsprogramm.Model.Client”类型 从范围'',但它没有定义

自己的解决方案:

不是最漂亮的解决方案,但它有效。

private ICriterion GetClientSearchCriterion()
{
    Conjunction conjunction = Restrictions.Conjunction();

    if (this.CurrentClientDetailViewModel.ClientId != 0)
    {
        conjunction.Add(Restrictions.Where<Client>(c => c.ClientId == this.CurrentClientDetailViewModel.ClientId));
        return conjunction;
    }

    if (!string.IsNullOrEmpty(this.CurrentClientDetailViewModel.Title))
    {
        conjunction.Add(Restrictions.Where<Client>(c => c.Title.IsLike(this.CurrentClientDetailViewModel.Title, MatchMode.Anywhere)));
    }
    if (!string.IsNullOrEmpty(this.CurrentClientDetailViewModel.FirstName))
    {
        conjunction.Add(Restrictions.Where<Client>(c => c.FirstName.IsLike(this.CurrentClientDetailViewModel.FirstName, MatchMode.Anywhere)));
    }
    if (!string.IsNullOrEmpty(this.CurrentClientDetailViewModel.LastName))
    {
        conjunction.Add(Restrictions.Where<Client>(c => c.LastName.IsLike(this.CurrentClientDetailViewModel.LastName, MatchMode.Anywhere)));
    }
    if (!string.IsNullOrEmpty(this.CurrentClientDetailViewModel.Street))
    {
        conjunction.Add(Restrictions.Where<Client>(c => c.Street.IsLike(this.CurrentClientDetailViewModel.Street, MatchMode.Anywhere)));
    }
    if (!string.IsNullOrEmpty(this.CurrentClientDetailViewModel.HouseNumber))
    {
        conjunction.Add(Restrictions.Where<Client>(c => c.HouseNumber.IsLike(this.CurrentClientDetailViewModel.HouseNumber, MatchMode.Anywhere)));
    }
    if (!string.IsNullOrEmpty(this.CurrentClientDetailViewModel.PostalCode))
    {
        conjunction.Add(Restrictions.Where<Client>(c => c.PostalCode.IsLike(this.CurrentClientDetailViewModel.PostalCode, MatchMode.Anywhere)));
    }
    if (!string.IsNullOrEmpty(this.CurrentClientDetailViewModel.City))
    {
        conjunction.Add(Restrictions.Where<Client>(c => c.City.IsLike(this.CurrentClientDetailViewModel.City, MatchMode.Anywhere)));
    }
    if (!string.IsNullOrEmpty(this.CurrentClientDetailViewModel.DateOfBirth))
    {
        conjunction.Add(Restrictions.Where<Client>(c => c.DateOfBirth.IsLike(this.CurrentClientDetailViewModel.DateOfBirth, MatchMode.Anywhere)));
    }
    if (!string.IsNullOrEmpty(this.CurrentClientDetailViewModel.PhoneNumber1))
    {
        conjunction.Add(Restrictions.Where<Client>(c => c.PhoneNumber1.IsLike(this.CurrentClientDetailViewModel.PhoneNumber1, MatchMode.Anywhere)));
    }
    if (!string.IsNullOrEmpty(this.CurrentClientDetailViewModel.PhoneNumber2))
    {
        conjunction.Add(Restrictions.Where<Client>(c => c.PhoneNumber2.IsLike(this.CurrentClientDetailViewModel.PhoneNumber2, MatchMode.Anywhere)));
    }
    if (!string.IsNullOrEmpty(this.CurrentClientDetailViewModel.MobileNumber))
    {
        conjunction.Add(Restrictions.Where<Client>(c => c.MobileNumber.IsLike(this.CurrentClientDetailViewModel.MobileNumber, MatchMode.Anywhere)));
    }
    if (!string.IsNullOrEmpty(this.CurrentClientDetailViewModel.Telefax))
    {
        conjunction.Add(Restrictions.Where<Client>(c => c.Telefax.IsLike(this.CurrentClientDetailViewModel.Telefax, MatchMode.Anywhere)));
    }
    if (!string.IsNullOrEmpty(this.CurrentClientDetailViewModel.Email))
    {
        conjunction.Add(Restrictions.Where<Client>(c => c.Email.IsLike(this.CurrentClientDetailViewModel.Email, MatchMode.Anywhere)));
    }

    return conjunction;
}

【问题讨论】:

    标签: c# nhibernate reflection iteration nhibernate-criteria


    【解决方案1】:

    你不能将任何你喜欢的东西放入必须由 ORM 转换为 SQL 的 lambda 中。
    您的 lambda 必须能够被转换为 SQL,而 SQL 不等同于诸如 GetTypeGetPropertyGetValue 之类的东西。

    您可以尝试动态构建Expression,而不是使用lambda,有点像question 的答案。

    【讨论】:

    • 嗯,好的,谢谢@Frédéric :) 我会用动态的Expression 试试看
    • 请注意,您不能直接使用 Microsoft 动态,因为这是针对 LINQ 的,queryover 不是。您必须切换到linq-to-nhibernate 才能使用它。但是你可以研究它的实现来找到如何动态地构建你自己的表达式。 (阅读此answer 的链接可能更直接。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多