我怎样才能让 NHibernate 映射到自定义 Class?
How can I get NHibernate to map to a custom Class?
我最近实际上问了一个非常相似的问题,但是虽然标题提到了 classes,但我的内容主要是指一个元组,并且(非常棒的)答案反映了这一点。当我尝试用 class 替换元组时,出现 TargetParameterCountException: Parameter count mismatch.
异常。
我有以下方法从数据库中获取结果列表。
public static IList<T> Find<T>(DetachedCriteria crit) where T : class
{
lock (_locker)
{
return crit.GetExecutableCriteria(InstanceSession)
.List<T>();
}
}
这通常效果很好。但是,我已经更改了一个调用上面方法的方法。
public IList<FooBarResult> FindResults(FooBarTask st)
{
return DataAccess.Find<FooBarResult>(DetachedCriteria.For<FooBarResult>()
.Add(Restrictions.Eq("Task", st))).ToList();
}
对此有效(因为我不想 return 整个 FooBarResult
,只是上面的某些列)。
public IList<MyCustomClass> FindResults(FooBarTask st)
{
var typeConstructor = typeof(MyCustomClass).GetConstructors()[0];
return DataAccess.Find<MyCustomClass>(DetachedCriteria.For<FooBarResult>()
.Add(Restrictions.Eq("Task", st))
.SetProjection(
Projections.ProjectionList()
.Add(
Projections.Property("FieldOne") //this is a DateTime
)
.Add(
Projections.Property("FieldTwo") //this is a Guid
)
.SetResultTransformer(Transformers.AliasToBeanConstructor(typeConstructor))
)
);
}
这是 class。
public class MyCustomClass
{
public MyCustomClass()
{
//placeholder
}
public MyCustomClass(DateTime FieldOne, Guid FieldTwo)
{
this.FieldOne = FieldOne;
this.FieldTwo = FieldTwo;
}
public DateTime FieldOne { get; set; }
public Guid FieldTwo { get; set; }
}
如前所述,当 运行 return crit.GetExecutableCriteria(InstanceSession).List<T>();
代码时,我得到一个 TargetParameterCountException: Parameter count mismatch.
异常。
有什么方法可以使它 return 成为我的 MyCustomClass
的列表?
我没有测试过这个,但你应该使用 Transformers.AliasToBean
查看别名以使转换器工作:
public IList<MyCustomClass> FindResults(FooBarTask st)
{
var typeConstructor = typeof(MyCustomClass).GetConstructors()[0];
return DataAccess.Find<MyCustomClass>(DetachedCriteria.For<FooBarResult>()
.Add(Restrictions.Eq("Task", st))
.SetProjection(
Projections.ProjectionList()
.Add(Projections.Property("FieldOne"), "FieldOne")
.Add(Projections.Property("FieldTwo"), "FieldTwo")
)
.SetResultTransformer(Transformers.AliasToBean(typeof(MyCustomClass)))
.List<MyCustomClass>()
}
这一行:
var typeConstructor = typeof(MyCustomClass).GetConstructors()[0];
您将获得第一个默认构造函数,其签名显然不匹配。最简单的解决方法是:
var typeConstructor = typeof(MyCustomClass).GetConstructors()[1];
但最干净的解决方案是沿着这些思路(未经测试,也有点简化):
var typeConstructor = GetMatchingConstructorOrThrow<MyCustomClass>
(typeof(DateTime), typeof(Guid));
// ...
private ConstructorInfo GetMatchingConstructorOrThrow<T>(params Type[] requiredSignature)
where T : class
{
foreach (var c in typeof(T).GetConstructors())
{
var currentSignature = c.GetParameters().Select(p => p.ParameterType);
if (currentSignature.SequenceEqual(requiredSignature))
{
return c;
}
}
throw new NoMatchingConstructorFoundException();
}
我最近实际上问了一个非常相似的问题,但是虽然标题提到了 classes,但我的内容主要是指一个元组,并且(非常棒的)答案反映了这一点。当我尝试用 class 替换元组时,出现 TargetParameterCountException: Parameter count mismatch.
异常。
我有以下方法从数据库中获取结果列表。
public static IList<T> Find<T>(DetachedCriteria crit) where T : class
{
lock (_locker)
{
return crit.GetExecutableCriteria(InstanceSession)
.List<T>();
}
}
这通常效果很好。但是,我已经更改了一个调用上面方法的方法。
public IList<FooBarResult> FindResults(FooBarTask st)
{
return DataAccess.Find<FooBarResult>(DetachedCriteria.For<FooBarResult>()
.Add(Restrictions.Eq("Task", st))).ToList();
}
对此有效(因为我不想 return 整个 FooBarResult
,只是上面的某些列)。
public IList<MyCustomClass> FindResults(FooBarTask st)
{
var typeConstructor = typeof(MyCustomClass).GetConstructors()[0];
return DataAccess.Find<MyCustomClass>(DetachedCriteria.For<FooBarResult>()
.Add(Restrictions.Eq("Task", st))
.SetProjection(
Projections.ProjectionList()
.Add(
Projections.Property("FieldOne") //this is a DateTime
)
.Add(
Projections.Property("FieldTwo") //this is a Guid
)
.SetResultTransformer(Transformers.AliasToBeanConstructor(typeConstructor))
)
);
}
这是 class。
public class MyCustomClass
{
public MyCustomClass()
{
//placeholder
}
public MyCustomClass(DateTime FieldOne, Guid FieldTwo)
{
this.FieldOne = FieldOne;
this.FieldTwo = FieldTwo;
}
public DateTime FieldOne { get; set; }
public Guid FieldTwo { get; set; }
}
如前所述,当 运行 return crit.GetExecutableCriteria(InstanceSession).List<T>();
代码时,我得到一个 TargetParameterCountException: Parameter count mismatch.
异常。
有什么方法可以使它 return 成为我的 MyCustomClass
的列表?
我没有测试过这个,但你应该使用 Transformers.AliasToBean
查看别名以使转换器工作:
public IList<MyCustomClass> FindResults(FooBarTask st)
{
var typeConstructor = typeof(MyCustomClass).GetConstructors()[0];
return DataAccess.Find<MyCustomClass>(DetachedCriteria.For<FooBarResult>()
.Add(Restrictions.Eq("Task", st))
.SetProjection(
Projections.ProjectionList()
.Add(Projections.Property("FieldOne"), "FieldOne")
.Add(Projections.Property("FieldTwo"), "FieldTwo")
)
.SetResultTransformer(Transformers.AliasToBean(typeof(MyCustomClass)))
.List<MyCustomClass>()
}
这一行:
var typeConstructor = typeof(MyCustomClass).GetConstructors()[0];
您将获得第一个默认构造函数,其签名显然不匹配。最简单的解决方法是:
var typeConstructor = typeof(MyCustomClass).GetConstructors()[1];
但最干净的解决方案是沿着这些思路(未经测试,也有点简化):
var typeConstructor = GetMatchingConstructorOrThrow<MyCustomClass>
(typeof(DateTime), typeof(Guid));
// ...
private ConstructorInfo GetMatchingConstructorOrThrow<T>(params Type[] requiredSignature)
where T : class
{
foreach (var c in typeof(T).GetConstructors())
{
var currentSignature = c.GetParameters().Select(p => p.ParameterType);
if (currentSignature.SequenceEqual(requiredSignature))
{
return c;
}
}
throw new NoMatchingConstructorFoundException();
}