您的位置:首页 > 其它

使用域超级管理员打开Exchange 2010发现没有权限

2012-03-28 23:33 417 查看
在项目中有这个一个需求,查询一个表,显示为datagrid,但是需要显示的一列是个关联表中的信息,是一对多的,但是需要把这个‘多’以逗号分隔显示在这一列上。

举例:

A1表 A2表

id name id A1_id name

1 name1 1 1 A2_name1

2 name2 2 1 A2_name2

3 2 A2_name3

查询后得到的显示在页面上的datagrid 应该为:

id name A2_name

1 name1 A2_name1, A2_name2

2 name2 A2_name3

如果用hibernate你会怎么做呢? 写sql语句,一个sql能直接写出这样的结果的sql吗? 我想了一下,很难,因为显示结果需要改变 A2表的维度,需要将关联的多条记录转化为 一条记录上的一列的值。有人说实话存储过程吧, 如果用存储过程了,那hibernate就失去了使用它的意义,在数据库移植上就会有问题。我们的原则是指做基本的sql处理,其他的都是业务逻辑代替。有人说,用hibernate查询A1表,然后得到结果的List,然后遍历这个List,拿到A1的id,关联查询A2表,或者A2的结果集,然后遍历A2,将A2的那么拼成字符串,然后构建新的Map对象,将A1的结果集的数据全都加入,然后将构建好的A2关联信息的以逗号分隔的字符串,加入到Map的一个列中去。 嗯,这样可以实现我们最终要的结果,但是,hibernate获得的结果集List,hibernate本身就需要循环jdbc的Resultset,然后将数据填充到实体对象或者Map对象当中去,然后组织成一个List对象。 然后你又需要再次遍历这个List对象,讲所有的数据取出来,关联查询,再重新组织成一个新的Map对象。 数据量小,列比较少,还可以将就,但是数据量大,列大,又该如何? 研究了一上午hibernate的方法,好像就没有这么干的。不知道hibernate是否本来就可以支持。 如果hibernate本身就有办法支持的话,请知道的朋友告知。 最后没招,就研究了hibernate的Transformers 并读了AliasedTupleSubsetResultTransformer的源代码,于是有了点子。我重写了AliasedTupleSubsetResultTransformer,代码如下:

public class XKAliasToBeanResultTransformer extends AliasedTupleSubsetResultTransformer
{
/**
*
*/
private static final long serialVersionUID = 5967847763983844234L;

private final Class<?> resultClass;
private boolean isInitialized;
private String[] aliases;
private Setter[] setters;

public XKAliasToBeanResultTransformer(Class<?> resultClass)
{
if (resultClass == null)
{
throw new IllegalArgumentException("resultClass cannot be null");
}
isInitialized = false;
this.resultClass = resultClass;
}

/**
* {@inheritDoc}
*/
public boolean isTransformedValueATupleElement(String[] aliases, int tupleLength)
{
return false;
}

public Object transformTuple(Object[] tuple, String[] aliases)
{
Object result;

if (!isInitialized)
{
initialize(aliases);
}
else
{
check(aliases);
}

// 关键代码
result = Initialization.getInstance().getApplicationContext().getBean(resultClass);

for (int i = 0; i < aliases.length; i++)
{
if (setters[i] != null)
{
setters[i].set(result, tuple[i], null);
}
}

return result;
}

private void initialize(String[] aliases)
{
PropertyAccessor propertyAccessor = new ChainedPropertyAccessor(new PropertyAccessor[] { PropertyAccessorFactory.getPropertyAccessor(resultClass, null),
PropertyAccessorFactory.getPropertyAccessor("field") });
this.aliases = new String[aliases.length];
setters = new Setter[aliases.length];
for (int i = 0; i < aliases.length; i++)
{
String alias = aliases[i];
if (alias != null)
{
this.aliases[i] = alias;
setters[i] = propertyAccessor.getSetter(resultClass, alias);
}
}
isInitialized = true;
}

private void check(String[] aliases)
{
if (!Arrays.equals(aliases, this.aliases))
{
throw new IllegalStateException("aliases are different from what is cached; aliases=" + Arrays.asList(aliases) + " cached=" + Arrays.asList(this.aliases));
}
}

public boolean equals(Object o)
{
if (this == o)
{
return true;
}
if (o == null || getClass() != o.getClass())
{
return false;
}

XKAliasToBeanResultTransformer that = (XKAliasToBeanResultTransformer) o;

if (!resultClass.equals(that.resultClass))
{
return false;
}
if (!Arrays.equals(aliases, that.aliases))
{
return false;
}

return true;
}

public int hashCode()
{
int result = resultClass.hashCode();
result = 31 * result + (aliases != null ? Arrays.hashCode(aliases) : 0);
return result;
}
}

上面“关键代码”的地方,原来的代码,只是resultClass.newInstance(); 我的修改其实很简单,就是使用spring的Context获取的bean而已,这样bean就可以被增强了,可以注入,可以支持事务了。于是,我们就可以在hibernate像实体对象填充数据的时机做任何的事情,包括我上面的需求,一旦hibernate像实体对象填充数据,就要调用set方法,在调用setId这个方法的时候,我们就能获得每条记录的id,然后可以查询关联表,组织处以逗号分隔的关联表多条记录的名称,然后填充到实体对象的某一个属性上。这样,查询完毕,我们获得的List中的实体对象,就已经包含了我们要的多表合并出的那列的值,我们只用json一下,返回前台,轻松的就可以在datagrid上显示出我们要的结果。

这样做的坏处,目前看只有一条,就是无法应对hibernate的升级,如果升级变动大,就需要修改调整代码了。

如果有朋友有更好的办法,可以提出交流,我的这种办法,有点简单粗暴,但是可以应对一切不可能完成的任务。 其实说白了,相当于在hibernate给实体对象填充数据的过程中拦截。
本文出自 “My Joy is my joy ~” 博客,转载请与作者联系!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐