C# NHibernate QueryByExample仅包括某些属性

C# NHibernate QueryByExample仅包括某些属性,c#,nhibernate,query-by-example,C#,Nhibernate,Query By Example,我已经创建了一个自定义属性选择器来接受构造函数中的数组,以说明搜索中应该包含哪些属性。只要没有组件类型,这种方法就可以很好地工作,但是我该如何处理这些组件类型呢?以下是一个例子: public class Customer { public virtual int Id { get; private set; } public virtual Name Name { get; set; } public virtual bool isPreferred { get; se

我已经创建了一个自定义属性选择器来接受构造函数中的数组,以说明搜索中应该包含哪些属性。只要没有组件类型,这种方法就可以很好地工作,但是我该如何处理这些组件类型呢?以下是一个例子:

public class Customer
{
    public virtual int Id { get; private set; }
    public virtual Name Name { get; set; }
    public virtual bool isPreferred { get; set; }


    //...etc
}

public class Name
{
        public string Title { get; set; }
        public string Firstname { get; set; }
        public string Lastname { get; set; }
        public string Fullname { get; }
}


public class CustomerPropertySelector : Example.IPropertySelector
    {
        private string[] _propertiesToInclude = { };

        public CustomerPropertySelector(string[] propertiesToInclude)
        {
            this._propertiesToInclude = propertiesToInclude;
        }

        public bool Include(object propertyValue, String propertyName, NHibernate.Type.IType type)
        {
            //...Checking for null and zeros etc, excluded for brevity

            if (!_propertiesToInclude.Contains(propertyName))
                return false;

            return true;
        }
   }
我想能够搜索的名字,但不一定最后。但是属性名是name,所以名字和姓氏似乎都是同一属性的一部分,类似于name.Firstname,通常作为标准,在这里似乎不起作用。最好的解决办法是什么

示例:

Customer exampleCust = new Customer(FirstName: "Owen");
IList<Customer> matchedCustomers = _custRepo.GetByExample(exampleCust, new string[] { "Name.FirstName" });

我不确定确定确定属性是否为组件类的最佳方法,欢迎提供任何关于如何改进代码的建议。

以下代码将替换您用于填充属性的逻辑。我把它从一个数组改为一个列表,这样我就可以使用Add方法了,因为我很懒,但我想你明白了。这仅适用于一个子级别的属性。对于n个级别,您需要递归

        List<string> _propertiesToInclude = new List<string>();

        Type t;
        var props = t.GetProperties();
        foreach (var prop in props)
        {
            if (prop.PropertyType.IsClass)
                foreach (var subprop in prop.PropertyType.GetProperties())
                    _propertiesToInclude.Add(string.Format("{0}.{1}", prop.Name, subprop.Name));
            else
                _propertiesToInclude.Add(prop.Name);
        }
List\u propertiesToInclude=newlist();
t型;
var props=t.GetProperties();
foreach(道具中的var道具)
{
if(prop.PropertyType.IsClass)
foreach(prop.PropertyType.GetProperties()中的变量subop)
_propertiesToInclude.Add(string.Format(“{0}.{1}”,prop.Name,subop.Name));
其他的
_propertiesToInclude.Add(属性名称);
}

我以为我有什么想法,但再次阅读您的问题时,您想知道为什么QBE NHibernate代码不适用于组件属性

[Test]
public void TestExcludingQBE()
{
        using (ISession s = OpenSession())
        using (ITransaction t = s.BeginTransaction())
        {
            Componentizable master = GetMaster("hibernate", null, "ope%");
            ICriteria crit = s.CreateCriteria(typeof(Componentizable));
            Example ex = Example.Create(master).EnableLike()
                .ExcludeProperty("Component.SubComponent");
            crit.Add(ex);
            IList result = crit.List();
            Assert.IsNotNull(result);
            Assert.AreEqual(3, result.Count);

            master = GetMaster("hibernate", "ORM tool", "fake stuff");
            crit = s.CreateCriteria(typeof(Componentizable));
            ex = Example.Create(master).EnableLike()
                .ExcludeProperty("Component.SubComponent.SubName1");
            crit.Add(ex);
            result = crit.List();
            Assert.IsNotNull(result);
            Assert.AreEqual(1, result.Count);
            t.Commit();
        }
    }
我认为您需要为名称部分创建子条件查询

也许是这样的:

public IList<Customer> GetByExample(Customer customer, string[] propertiesToExclude){
    Example customerQuery = Example.Create(customer);
    Criteria nameCriteria = customerQuery.CreateCriteria<Name>();
    nameCriteria.Add(Example.create(customer.Name));
    propertiesToExclude.ForEach(x=> customerQuery.ExcludeProperty(x));
    propertiesToExclude.ForEach(x=> nameCriteria.ExcludeProperty(x));
    return customerQuery.list();
}

我想你对这个问题有点误解了-问题不在于决定如何填充
\u properties包括
,而是给定了数组如何告诉QBE我想从比较中排除
Name.LastName
,而不是
Name.FirstName
。我认为这可能是不可能的,因为就QBE而言,
Name
是一个整体,我可以包含也可以不包含,但不能部分包含。因此,您需要
CustomerPropertySelector.include(null,“Name.FirstName”,IType.Something)
返回
true
CustomerPropertySelector.Include(null,“Name.LastName”,IType.Something)
返回
false
?基于什么标准?难道你不能硬编码方法以排除Name.LastName吗?我想我一定是漏掉了重点。我也这么认为,也许我没有正确地回答这个问题。我想创建一个示例customer
new customer(FirstName:“Owen”)
,然后用
propertiesToInclude:new string[]{“Name.FirstName”}
将其传递给我的方法,然后该方法将只基于该字段比较对象。
typeof(string).IsClass
返回true,所以这在具有字符串属性的类上不起作用。我想没有比循环检查所有基本类型更好的方法了。我认为你用“QBE NHibernate代码不能处理组件属性”一针见血。是否有一个引用可以证实这一点?问题是QBE不知道是否包括/排除对象的组件部分,除非您专门将组件条件添加到查询中。我已经完全放弃在应用程序中使用QBE,转而使用以下API(按优先顺序)。Linq,QueryOver,Criteria,HQL。在我的最后一条评论之后,我在NHibernate测试项目中发现了一些代码,这些代码显示了如何从QBE查询中排除组件属性。啊哈!非常感谢您的跟进,这让我意识到了答案。QBE确实支持组件属性,我只是对如何做感到困惑。不幸的是,therealmitchconnors的答案更接近事实,尽管没有NHTest的例子,我永远也不会明白这一点。
[Test]
public void TestExcludingQBE()
{
        using (ISession s = OpenSession())
        using (ITransaction t = s.BeginTransaction())
        {
            Componentizable master = GetMaster("hibernate", null, "ope%");
            ICriteria crit = s.CreateCriteria(typeof(Componentizable));
            Example ex = Example.Create(master).EnableLike()
                .ExcludeProperty("Component.SubComponent");
            crit.Add(ex);
            IList result = crit.List();
            Assert.IsNotNull(result);
            Assert.AreEqual(3, result.Count);

            master = GetMaster("hibernate", "ORM tool", "fake stuff");
            crit = s.CreateCriteria(typeof(Componentizable));
            ex = Example.Create(master).EnableLike()
                .ExcludeProperty("Component.SubComponent.SubName1");
            crit.Add(ex);
            result = crit.List();
            Assert.IsNotNull(result);
            Assert.AreEqual(1, result.Count);
            t.Commit();
        }
    }