到这里还有一个重要工作没有说,就是上面代码中的如下语句:

Code
GoodsUserCredits.SetUserCredit(goodsrateinfo, goodsrateinfo.Uidtype == 1 ? goodstradelog.Buyerid :
goodstradelog.Sellerid);
在解释上面方法之前有必要先介绍一下关于信用机制显示数据的一些设计思想。请先看一下“信用评价”的页面截图:

附件:
您所在的用户组无法下载或查看附件 当前用户(截图中是admin)的评价按日期分为:最近一周,最近一个月,最近六个月,六个月前。按类型又分为:好评,中评,差评。而这些数字如果在显示时进行实时统计的话(实时查询上面的dnt_goodsrates表),在页面响应时间上会很慢,因为要做的查询“工作量”上实在是太大了,让人“无法接受”,因此这里我引入了一个数据表来记录要显示的相应数据,也就是dnt_goodsusercredits,下面即是该数据表的字典截图:

附件:
您所在的用户组无法下载或查看附件 这样我们就可以通过相应的数据行来显示“信用评价页面”中的各行内容了,这样做一是优化查询(只要一次查询)即可,二是数据与前台页面对应关系明确,一目了然。
当然,在这里我们需要一些当前用户的信用初始化数据,用于在日后有评价记录进入系统时来累加该表中的相应字段,而这项工作也交给了上面所述的方法GoodsUserCredits.SetUserCredit。
通过上面的介绍之后,我们就来看一下实际的代码是如何实现这些功能的。请看下面的SetUserCredit方法声明(位于App_Code文件夹下的GoodsUserCredits.cs文件):

Code
/// <summary>
/// 设置用户信用(该方法会在用户进行评价之后调用)
/// </summary>
/// <param name="goodsrateinfo">评价信息</param>
/// <param name="uid">被评价人的uid</param>
/// <returns></returns>
public static bool SetUserCredit(Goodsrateinfo goodsrateinfo, int uid)
{
//获取被评价人的信用信息
GoodsusercreditinfoCollection goodsusercreditinfocoll = GetUserCreditList(uid);
//如果信用表中不存在, 则创建被评价人的信息
if (goodsusercreditinfocoll.Count == 0)
{
//当初始化信息失败时则返回
if (DbProvider.GetInstance().InitGoodsUserCredit(uid) <= 0)
{
return false;
}
//再次获取被评价人的信用信息
goodsusercreditinfocoll = GetUserCreditList(uid);
}
//用于绑定要更新的用户信用
Goodsusercreditinfo cur_creditinfo = null;
foreach (Goodsusercreditinfo goodsusercreditinfo in goodsusercreditinfocoll)
{
//查找符合条件的用户信用
if (goodsrateinfo.Uidtype == goodsusercreditinfo.Ratefrom && goodsrateinfo.Ratetype ==
goodsusercreditinfo.Ratetype)
{
cur_creditinfo = goodsusercreditinfo; break;
}
}
//当不为空, 表示找到了要更新的用户信用信息, 则进行下面的绑定操作
if (cur_creditinfo != null)
{
IDataReader __idatareader = DbProvider.GetInstance().GetGoodsRateCount(uid,
goodsrateinfo.Uidtype, goodsrateinfo.Ratetype);
//绑定新的查询数据
if (__idatareader.Read())
{
cur_creditinfo.Ratefrom = goodsrateinfo.Uidtype;
cur_creditinfo.Ratetype = goodsrateinfo.Ratetype;
cur_creditinfo.Oneweek = Convert.ToInt32(__idatareader["oneweek"].ToString());
cur_creditinfo.Onemonth = Convert.ToInt32(__idatareader["onemonth"].ToString());
cur_creditinfo.Sixmonth = Convert.ToInt32(__idatareader["sixmonth"].ToString());
cur_creditinfo.Sixmonthago = Convert.ToInt32(__idatareader["sixmonthago"].ToString());
UpdateUserCredit(cur_creditinfo);
}
__idatareader.Close();
}
return true;
}
上面代码段中的第一行即是获取相应的用户信用记录的方法,其返回的是一个GoodsusercreditinfoCollection类型,该类型是一个集合类型,而GetUserCreditList方法声明如下所示:

Code
/// <summary>
/// 获取指定用户id的信用信息
/// </summary>
/// <param name="userid">用户id</param>
/// <returns></returns>
public static GoodsusercreditinfoCollection GetUserCreditList(int userid)
{
return DTO.GetGoodsUserCreditList(DbProvider.GetInstance().GetGoodsUserCreditByUid(userid));
}
该函数用于将数据表中查询的信用数据转换(DTO)成为集合类型,而其GetGoodsUserCreditByUid方法所执行的查询语句如下所示(注:这里要返回的记录行数为6,即是上面信用页面截图中所列的6行数据):

Code
/// <summary>
/// 获取指定用户id的评价信息
/// </summary>
/// <param name="uid">用户id</param>
/// <returns></returns>
public IDataReader GetGoodsUserCreditByUid(int uid)
{
DbParameter parm = DbHelper.MakeInParam("@uid", (DbType)SqlDbType.Int, 4, uid);
return DbHelper.ExecuteReader(CommandType.Text, string.Format("SELECT * FROM [{0}goodsusercredits]
WHERE [uid] = @uid ORDER BY [id] ASC", BaseConfigs.GetTablePrefix), parm);
}
而上面SetUserCredit方法中的如下代码,即是在尚无用户初始数据时来进行初始化操作的:

Code
//如果信用表中不存在, 则创建被评价人的信息
if (goodsusercreditinfocoll.Count == 0)
{
//当初始化信息失败时则返回
if (DbProvider.GetInstance().InitGoodsUserCredit(uid) <= 0)
{
return false;
}
//再次获取被评价人的信用信息
goodsusercreditinfocoll = GetUserCreditList(uid);
}
其SQL语句如下所示(注:插入了6行数据):

Code
/// <summary>
/// 初始化用户评价信息
/// </summary>
/// <param name="userid">用户id</param>
/// <returns></returns>
public int InitGoodsUserCredit(int userid)
{
DbParameter[] parms =
{
DbHelper.MakeInParam("@uid", (DbType)SqlDbType.Int, 4,userid),
};
StringBuilder sb_sql = new StringBuilder();
sb_sql.Append("INSERT INTO [" + BaseConfigs.GetTablePrefix + "goodsusercredits] ([uid],[ratefrom],[ratetype]) VALUES (@uid, 2, 1);");
sb_sql.Append("INSERT INTO [" + BaseConfigs.GetTablePrefix + "goodsusercredits] ([uid],[ratefrom],[ratetype]) VALUES (@uid, 2, 2);");
sb_sql.Append("INSERT INTO [" + BaseConfigs.GetTablePrefix + "goodsusercredits] ([uid],[ratefrom],[ratetype]) VALUES (@uid, 2, 3);");
sb_sql.Append("INSERT INTO [" + BaseConfigs.GetTablePrefix + "goodsusercredits] ([uid],[ratefrom],[ratetype]) VALUES (@uid, 1, 1);");
sb_sql.Append("INSERT INTO [" + BaseConfigs.GetTablePrefix + "goodsusercredits] ([uid],[ratefrom],[ratetype]) VALUES (@uid, 1, 2);");
sb_sql.Append("INSERT INTO [" + BaseConfigs.GetTablePrefix + "goodsusercredits] ([uid],[ratefrom],[ratetype]) VALUES (@uid, 1, 3);SELECT SCOPE_IDENTITY() AS 'id';");
return Utils.StrToInt(DbHelper.ExecuteDataset(CommandType.Text, sb_sql.ToString(), parms).Tables[0].Rows[0][0].ToString(), -1);
}
在初始化相应数据后再次实例化goodsusercreditinfocoll对象,以便在接下来的代码中进行数据更新绑定,如下所示:

Code
//用于绑定要更新的用户信用
Goodsusercreditinfo cur_creditinfo = null;
foreach (Goodsusercreditinfo goodsusercreditinfo in goodsusercreditinfocoll)
{
//查找符合条件的用户信用
if (goodsrateinfo.Uidtype == goodsusercreditinfo.Ratefrom && goodsrateinfo.Ratetype == goodsusercreditinfo.Ratetype)
{
cur_creditinfo = goodsusercreditinfo; break;
}
}
//当不为空, 表示找到了要更新的用户信用信息, 则进行下面的绑定操作
if (cur_creditinfo != null)
{
IDataReader __idatareader = DbProvider.GetInstance().GetGoodsRateCount(uid,
goodsrateinfo.Uidtype, goodsrateinfo.Ratetype);
//绑定新的查询数据
if (__idatareader.Read())
{
cur_creditinfo.Ratefrom = goodsrateinfo.Uidtype;
cur_creditinfo.Ratetype = goodsrateinfo.Ratetype;
cur_creditinfo.Oneweek = Convert.ToInt32(__idatareader["oneweek"].ToString());
cur_creditinfo.Onemonth = Convert.ToInt32(__idatareader["onemonth"].ToString());
cur_creditinfo.Sixmonth = Convert.ToInt32(__idatareader["sixmonth"].ToString());
cur_creditinfo.Sixmonthago = Convert.ToInt32(__idatareader["sixmonthago"].ToString());
UpdateUserCredit(cur_creditinfo);
}
__idatareader.Close();
}
这样,我们可在新创建信用数据之后用已存在的信用数据来更新已有的信用评价记录数了(参见信用页面截图)。
当然说到这里,还有一个问题没有解决,就是数据时效性的问题。因为从上面的代码中可以看出,只有在发生评价行为时,才会更新相应的数据,而如果用户很长时间没有进行交易的话,数据是不会进行更新的,而该问题的解决方案包括:
1. 可以在用户登陆时进行异步统计更新
2. 可在后台加入计划任务,以便在指定时间对全部用户的交易信用数据进行统计
3. 在上述方面中直接进行更新
当然目前还没有最终实现,因为还不排除存在“更优解决方案”的可能性。当然这里所造成的问题并不十分严重,因为在好评率上不会因为这个问题而造成误差,同时评价信息也未受到影响,这会为将来解决方案出台后进行信息统计提供可靠的数据支持。
到这时,主要的业务逻辑和设计思路解释完了,而相应的页面数据显示基本上是使用了ajax +js进行开发的,相关内容大家可以参见相应的模板(eccredit.htm)及js文件(template_eccredit.js)说明。这里就不多加说明了。
当然,这里的信用机制还缺少一些分支流程的支持。比如因为买卖双方的“误操作”,造成评价信息的不准确。所以应该提供“申诉(投诉)机制”来让管理员或双方介入修改相应的评价信息数据等。而这些都有待日后进一步完善设计。
好了,今天的内容就先到这里了。
关于DiscuzNT交易插件介绍的系列文章到此就要告一段落了, 谢谢大家的支持和关注:)
作者: 代震军, daizhj
原帖链接:
http://www.cnblogs.com/daizhj/archive/2008/08/26/1276467.html