C# NHibernate—不带';物理.NET样式属性';

C# NHibernate—不带';物理.NET样式属性';,c#,nhibernate,C#,Nhibernate,ICompositeUserType接口的XML注释告诉我: This interface allows a custom type to define "properties". --> These need not necessarily correspond to physical .NET style properties. 在这种情况下,我将多个列映射到一个列表中: // Each column is mapped into this object public class I

ICompositeUserType
接口的XML注释告诉我:

This interface allows a custom type to define "properties".
--> These need not necessarily correspond to physical .NET style properties.
在这种情况下,我将多个列映射到一个列表中:

// Each column is mapped into this object
public class IdentifiedValue
{
    public string Name;
    public object Value;
}

public class CompanyContainer
{
    public virtual int Id { get; set; }
    public virtual IList<IdentifiedValue> Values { get; set; }
}

// The columns being mapped:
public class GeneratedColumns
{
    public static string[] ColumnsInfo
    {
        get
        {
            return new[]
                {
                    "CODE_TYPE",
                    "CODE_VALUE",
                    "CODE_DESC_NL",
                    "CODE_DESC_FR",
                    "CODE_DESC_EN"
                };
        }
    }
}
//每个列都映射到此对象中
公共类识别值
{
公共字符串名称;
公共客体价值;
}
公共类公司容器
{
公共虚拟整数Id{get;set;}
公共虚拟IList值{get;set;}
}
//要映射的列:
公共类生成列
{
公共静态字符串[]列信息
{
得到
{
返回新的[]
{
“代码类型”,
“代码值”,
“代码描述”,
“代码说明”,
“代码描述”
};
}
}
}
ICompositeUserType的实现: (不相关的方法省略)

公共类IdentifiedValueMapper:ICompositeUserType
{
公共字符串[]属性名称
{
得到
{
var result=新列表();
foreach(GeneratedColumns.ColumnsInfo中的var columnInfo)
{
结果.添加(columnInfo);
}
返回result.ToArray();
}
}
公共对象NullSafeGet(IDataReader dr、字符串[]名称、ISessionImplementor会话、对象所有者)
{
如果(dr==null)
{
返回null;
}
var result=新列表();
for(int i=0;i
映射本身

public class CompanyContainerMap : ClassMap<CompanyContainer>
{
    public CompanyContainerMap()
    {
        Table("S1073_CODE");
        Id(x => x.Id).Column("CODE_ID");
        var cols = Map(x => x.Values)
            .CustomType<IdentifiedValueMapper>()
            .Columns.Clear();

        foreach (var col in GeneratedColumns.ColumnsInfo)
        {
            cols.Columns.Add(col);
        }
    }
}
公共类公司容器映射:类映射
{
上市公司ContainerMap()
{
表(“S1073_代码”);
Id(x=>x.Id).Column(“CODE_Id”);
var cols=Map(x=>x.Values)
.CustomType()
.Columns.Clear();
foreach(GeneratedColumns.ColumnsInfo中的变量col)
{
cols.Columns.Add(col);
}
}
}
失败的测试代码:

    [TestMethod]
    public void TestMethod1()
    {
        var factory = BuildSessionFactory();

        using (var session = factory.OpenSession())
        {
            var query = session.QueryOver<CompanyContainer>();
            query.Where(Restrictions.Eq("CODE_VALUE", "1"));
            var result = query.List();
            var blah = result;
        }
    }
[TestMethod]
公共void TestMethod1()
{
var factory=BuildSessionFactory();
使用(var session=factory.OpenSession())
{
var query=session.QueryOver();
查询.其中(限制.Eq(“代码值”,“1”));
var result=query.List();
var blah=结果;
}
}
执行查询时出现异常:
无法解析属性:code\u的值:CompanyContainer

所以看起来它仍在试图访问不存在的CompanyContainer.CODE_值。我不确定它为什么要访问.NET属性,因为我只想生成
WHERE code\u VALUE='1'


在没有Where子句的情况下执行可以正常工作。

因为文档不是很好,所以很难识别此类内容

我对nhibernate代码进行了调试,发现nhibernate只需要为存储在Value中的属性列表指定一个特定的属性路径

路径是
,因此您可以使用如下内容:

query.Where(Restrictions.Eq("Values.CODE_VALUE", "1"));
顺便说一下,您也可以通过使用动态零部件映射来实现相同的结果

在映射中,使用以下命令

DynamicComponent(p => p.Values, m =>
{
    foreach (var col in GeneratedColumns.ColumnsInfo)
    {
        m.Map(col).CustomSqlType("nvarchar(50)");
    }
});
代替您的值映射,使用例如
IDictionary
作为值的类型

public virtual IDictionary Values { get; set; }
这将生成相同的表结构,并将所有值检索到字典中

查询的工作方式完全相同

我认为这样代码更容易理解,并且您可以摆脱
ICompositeUserType
实现

要创建更安全的类型,可以为列定义添加对象类型和sql类型列表

public static string[] ColumnSqlTypes
{
    get
    {
        return new[]
        {
            "nvarchar(50)",
            "int",
            "nvarchar(255)",
            "nvarchar(255)",
            "nvarchar(255)"
        };
    }
}

public static Type[] ColumnTypes
{
    get
    {
        return new[]
        {
            typeof(string),
            typeof(Int32),
            typeof(string),
            typeof(string),
            typeof(string)
        };
    }
}
并将映射更改为

public class CompanyContainerMap : ClassMap<CompanyContainer>
{
    public CompanyContainerMap()
    {
        Table("S1073_CODE");
        Id(x => x.Id).Column("CODE_ID");
        DynamicComponent(p => p.Values, m =>
        {
            for(var index = 0; index < GeneratedColumns.ColumnsInfo.Length; index++)
            {
                m.Map(GeneratedColumns.ColumnsInfo[index])
                    .CustomSqlType(GeneratedColumns.ColumnSqlTypes[index])
                    .CustomType(GeneratedColumns.ColumnTypes[index]);
            }
        });
    }
}
它将抛出一个异常,因为它期望代码值为整数

改成

query.Where(Restrictions.Eq("Values.CODE_VALUE", 1));
很好用

query.Where(Restrictions.Eq("Values.CODE_VALUE", "1"));
query.Where(Restrictions.Eq("Values.CODE_VALUE", 1));