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));