[英]How to incorporate property value conversion into NHibernate QueryOver .SelectList?
我希望將屬性值轉換合並到我的QueryOver查詢中。
我喜歡在查詢對象模式之后編寫查詢,直接生成MVC視圖模型。 在我的視圖模型中,我嘗試使用盡可能簡單的屬性類型,將轉換復雜性保留在視圖和控制器之外。 這意味着有時候,我需要將一種類型轉換為另一種類型,例如將日期轉換為字符串。
有人可能會爭辯說,這種轉換應該在視圖中執行,但由於我的大多數視圖模型都直接轉換為JSON對象,這會導致轉換變得更加麻煩。 在JavaScript中執行日期到字符串轉換充其量是有問題的,我的JSON轉換器不夠靈活。
這是我正在做的一個例子:
// Entity.
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public DateTimeOffset DateCreated { get; set; }
}
// View model.
public class CustomerViewModel
{
public string Name { get; set; }
public string DateCreated { get; set; } // Note the string type here.
}
// Query.
CustomerViewModel model = null;
List<CustomerViewModel> result = Session.QueryOver<Customer>()
.SelectList(list => list
.Select(n => n.Name).WithAlias(() => model.Name)
.Select(n => n.DateCreated).WithAlias(() => model.DateCreated))
.TransformUsing(Transformers.AliasToBean<CustomerViewModel>());
.Future<CustomerViewModel>()
.ToList();
運行查詢代碼時,拋出以下異常:
Object of type 'System.DateTimeOffset' cannot be converted to type 'System.String'.
顯然,這是因為以下幾行:
.Select(n => n.DateCreated).WithAlias(() => model.DateCreated))
所以問題是:如何將日期轉換為字符串轉換為查詢?
我不想在執行查詢后執行轉換,因為在轉換它們之前我需要一個額外的中間類來存儲結果。
List<CustomerViewModel> result = Session.QueryOver<Customer>(() => customerAlias)
.SelectList(list => list
.Select(n => customerAlias.Name).WithAlias(() => model.Name)
// I'm not sure if customerAlias works here or why you have declared it at all
.Select(Projections.Cast(NHibernateUtil.String, Projections.Property<Customer>(c => c.DateCreated))).WithAlias(() => model.DateCreated))
.TransformUsing(Transformers.AliasToBean<CustomerViewModel>());
.Future<CustomerViewModel>()
.ToList();
應該工作但不幸的是沒有給你任何控制字符串的格式。 我通過在模型上定義一個私有屬性來處理類似的問題,該屬性將數據保存為正確的類型,並使用字符串屬性來返回格式化的值,即:
public class CustomerViewModel
{
public string Name { get; set; }
private DateTime DateCreatedImpl { get; set; }
public string DateCreated { get { return DateCreatedImpl.ToString(); }}
}
這有幾個優點,但可能不適合您的JSON轉換器。 您的轉換器是否具有允許其忽略私有屬性的設置或屬性?
我今天遇到了同樣的問題,看到了這個帖子。 我繼續創建了自己的變換器,可以使用Converter函數來處理每個屬性的類型轉換。
這是Transformer類。
public class AliasToDTOTransformer<D> : IResultTransformer where D: class, new()
{
//Keep a dictionary of converts from Source -> Dest types...
private readonly IDictionary<Tuple<Type, Type>, Func<object, object>> _converters;
public AliasToDTOTransformer()
{
_converters = _converters = new Dictionary<Tuple<Type, Type>, Func<object, object>>();
}
public void AddConverter<S,R>(Func<S,R> converter)
{
_converters[new Tuple<Type, Type>(typeof (S), typeof (R))] = s => (object) converter((S) s);
}
public object TransformTuple(object[] tuple, string[] aliases)
{
var dto = new D();
for (var i = 0; i < aliases.Length; i++)
{
var propinfo = dto.GetType().GetProperty(aliases[i]);
if (propinfo == null) continue;
var valueToSet = ConvertValue(propinfo.PropertyType, tuple[i]);
propinfo.SetValue(dto, valueToSet, null);
}
return dto;
}
private object ConvertValue(Type destinationType, object sourceValue)
{
//Approximate default(T) here
if (sourceValue == null)
return destinationType.IsValueType ? Activator.CreateInstance(destinationType) : null;
var sourceType = sourceValue.GetType();
var tuple = new Tuple<Type, Type>(sourceType, destinationType);
if (_converters.ContainsKey(tuple))
{
var func = _converters[tuple];
return Convert.ChangeType(func.Invoke(sourceValue), destinationType);
}
if (destinationType.IsAssignableFrom(sourceType))
return sourceValue;
return Convert.ToString(sourceValue); // I dunno... maybe throw an exception here instead?
}
public IList TransformList(IList collection)
{
return collection;
}
以下是我如何使用它,首先是我的DTO:
public class EventDetailDTO : DescriptionDTO
{
public string Code { get; set; }
public string Start { get; set; }
public string End { get; set; }
public int Status { get; set; }
public string Comment { get; set; }
public int Client { get; set; }
public int BreakMinutes { get; set; }
public int CanBeViewedBy { get; set; }
}
稍后當我調用我的查詢時,它將Start和End作為DateTime值返回。 這就是我實際使用轉換器的方式。
var transformer = new AliasToDTOTransformer<EventDetailDTO>();
transformer.AddConverter((DateTime d) => d.ToString("g"));
希望這可以幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.