繁体   English   中英

如何将属性值转换合并到NHibernate QueryOver .SelectList?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM