分享下我写不需要太严谨的项目的代码风格

2015-11-19 11:41:03 +08:00
 dbfox
public static Common.DB.ResultList GetList(Common.DB.NVCollection queryParams)
{

//string pageString = queryParams["page"] as string ?? "1";
//string psString = queryParams["pagesize"] as string ?? string.Empty;
//string cidString = queryParams["cid"] as string ?? string.Empty;

string sort = queryParams["sort"] as string ?? string.Empty;
string cate = queryParams["cate"] as string ?? string.Empty;
string type = queryParams["type"] as string ?? string.Empty;
string ch = queryParams["ch"] as string ?? string.Empty;
string kind = queryParams["kind"] as string ?? string.Empty;

string andwhere = "1=1";
string rootKey = null;
switch (type)
{
case "appsoft":
rootKey = "iphones";
break;
case "appgame":
rootKey = "iphoneg";
break;
case "azsoft":
rootKey = "soft";
break;
case "azgame":
rootKey = "game";
break;
}

var pnvc = new Common.DB.NVCollection();

if (rootKey != null)
{
var pcate = DBCache.SoftCategoryCache.Get(rootKey);
if (pcate != null)
{
andwhere += " and charIndex(@path,categoryPath)>0 ";
pnvc["path"] = "/" + pcate.ID + "/";
}
}

if (ch == "az")
{
andwhere += " and (charIndex(@path1,categoryPath)>0 or charIndex(@path2,categoryPath)>0)";
pnvc["path1"] = "/" + DBCache.SoftCategoryCache.Get("game").ID + "/";
pnvc["path2"] = "/" + DBCache.SoftCategoryCache.Get("soft").ID + "/";
}
else if (ch == "app")
{
andwhere += " and (charIndex(@path1,categoryPath)>0 or charIndex(@path2,categoryPath)>0)";
pnvc["path1"] = "/" + DBCache.SoftCategoryCache.Get("appgame").ID + "/";
pnvc["path2"] = "/" + DBCache.SoftCategoryCache.Get("appsoft").ID + "/";
}


if (!string.IsNullOrEmpty(cate) && !string.IsNullOrEmpty(rootKey))
{
var cateEnt = DBCache.SoftCategoryCache.Get(rootKey, cate);

if (cateEnt != null)
{
andwhere += " and categoryid=@cid ";
pnvc["cid"] = cateEnt.ID;
}
}




int cid = (queryParams["cid"] as int?) ?? 0;
if (cid > 0)
{
var cateEnt = DBCache.SoftCategoryCache.Get(cid);

if (cateEnt != null)
{
andwhere += " and categoryid=@cid ";
pnvc["cid"] = cateEnt.ID;
}
}

string orderby = " id desc";
switch (sort)
{
case "new":
orderby = " id desc";
break;
case "hot":
orderby = " viewTimes desc,id desc";
break;
case "rank":
orderby = " downWeekTimes desc,id desc";

break;
default:
break;
}

switch (kind)
{
case "number":
andwhere += " and number>0";
orderby = " number desc,id desc ";
break;
case "hprec":
andwhere += " and recommend=1 and homepage=1 and number=0 ";
orderby = " viewtimes desc,id desc ";
break;
case "recnothp":
andwhere += " and recommend=1 and homepage=0 and number=0 ";
orderby = " viewtimes desc,id desc ";
break;
case "rec":
andwhere += " and recommend=1 ";
break;

case "all":

break;

case "normal":
default:
andwhere += " and recommend=0 and homepage=0 and number=0 ";
//orderby = " id desc ";
break;
}





int page = (queryParams["page"] as int?) ?? 1;
if (page <= 0)
{
page = 1;
}

int pagesize = (queryParams["pagesize"] as int?) ?? 10;

if (pagesize <= 0)
{
pagesize = 10;
}

Common.DB.ResultList result = new Common.DB.ResultList(pagesize);

var dbh = Common.DB.Factory.Default;

//List<Common.DB.NVCollection> list = new List<Common.DB.NVCollection>(pagesize);

var query = Common.DB.Factory.DefaultPagerQuery;
query.AbsolutePage = page;
query.Fields = "id,name,version,viewtimes,categoryid";
query.PageSize = pagesize;
query.Sort = orderby;
query.Table = "soft";
query.Where = andwhere;

string csql = query.GetCountQueryString();
string qsql = query.GetQueryString();

int rc = dbh.ExecuteScalar<int>(csql, pnvc);
var ls = dbh.GetDataList(qsql, pnvc);

int pc = Convert.ToInt32(Math.Ceiling((decimal)rc / (decimal)pagesize));


result.Page = page;
result.PageCount = pc;
result.RecordCount = rc;
result.PageSize = pagesize;

for (int i = 0; i < ls.Count; i++)
{
var o = ls[i];

var ent = new Common.DB.NVCollection();
var entcate = DBCache.SoftCategoryCache.Get((int)o["categoryid"]);

ent["id"] = o["id"];
ent["name"] = o["name"];
ent["version"] = o["version"];
ent["cid"] = o["categoryid"];
ent["cpath"] = Services.PathService.GetListPath(entcate);
ent["cname"] = entcate.Name;
ent["path"] = Services.PathService.GetPath(entcate, (int)o["id"]);
ent["dtimes"] = o["viewtimes"];

result.Add(ent);
}

return result;
}
4436 次点击
所在节点    程序员
44 条回复
jarlyyn
2015-11-20 10:02:22 +08:00
@dbfox

1.这和类型有什么关系?这是你的代码没有合适的函数话好不?正常代码不是主流程表逻辑,业务丢函数么?谁能一眼看清你这代码做了什么?你让以后接收修改你这程序的甚至是半年后的自己情何以堪?

2.不要手工拼接 sql 和 orm 有什么关系? orm 是把数据模型化吧?对应手工拼接 Sql 的不是 prepara 么……

所以说你需要好好研究下框架的代码,不是说框架代码有多优秀,而是看看成熟的代码怎么去处理这些坑。
dbfox
2015-11-20 10:12:27 +08:00
@jarlyyn

1 、 我这里 应当算数据访问层,不太刻意追求分层,复杂的地方 会有封装,但绝不可以追求分层。可能我们不在一个领域

2 、 prepara .net 下有这玩意儿?

框架我一点都不喜欢,只想掌握最根本的东西,万变不离其宗
jarlyyn
2015-11-20 10:27:11 +08:00
@dbfox

1.这个是所有代码最基本的地方,和你什么层没关系。和怎么写出一个可以维护的代码有关。

2.prepara 是数据的事情。 mysql 可以,我查过 sqlserver 也可以。这个和.net 有什么关系?随便搜索一下

https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.prepare(v=vs.110).aspx

其他的不多说了。祝您写代码快乐。
dbfox
2015-11-20 13:48:49 +08:00
@jarlyyn

听得我听腻歪,找张图片回复你吧:




SqlCommand.Prepare
对重复要执行的语句,使用这个方法可以提高执行效率。
跟我拼接 sql 有毛关系???
jarlyyn
2015-11-20 14:16:33 +08:00
@dbfox

好的,我犯贱。

v2ex 是不能删帖子的。

只怕您以后在 V2EX 找工作的话会暴露水平。

祝一切顺风。
ewBuyVmLZMZE
2015-11-20 14:28:50 +08:00
这代码看得我尿崩。
fwrq41251
2015-11-20 14:33:38 +08:00
静态语言当成动态语言来用.缺点 LZ 也说了:"ide 无法自动提示参数和类型,需要手工去写比较详细的注释和类型".规模小的时候这样开发是会比较快速.可维护性好就不一定了,比如你的 queryParams 里的某个 field 的类型或者名字变化了,而用到这个 queryParams 的地方又很多,如果你定义了它的类型和名称用 IDE 可以很轻松的重构所有需要修改的地方,而像现在这样写,维护起来就比较痛苦了.这也是像 java 这样一种啰嗦的语言的优势所在.
leassy
2015-11-20 14:34:51 +08:00
楼主写 C#啊,看着好亲切
xujif
2015-11-20 14:40:24 +08:00
第一个阶段,拼接
第二个阶段,参数封装
第三个阶段, orm
第四个阶段, orm+复杂查询,比如 mybatis 之类封装语句
之后,基本就变成仓储模式,不关心数据放在哪里
楼主既然是 c#,不用 linq 这等神器吗,就算不用 ef , linq to sql 也有不少 provider 可以用吧。
msg7086
2015-11-20 15:22:54 +08:00
说了半天其实就想说这个 KeyValuePair 的 Collection 拿来传参数?
别闹了,看看这个吧: https://msdn.microsoft.com/en-us/library/dd264739.aspx

至于拼接 SQL 我就不多吐槽了,大家已经吐了很多了。
不用关系代数而用字符串,这本来就是坏的编程风格了,都不用去看效率高低。

总之我只希望初学者不要被这样的代码风格影响就好。
iamppz
2015-11-22 13:23:41 +08:00
写得非常好,请继续坚持







坚持几年你就明白了
dbfox
2015-11-22 20:19:30 +08:00
@jarlyyn 不要激动,讨论个代码而已

只是不明白你说的要怎么写,这样写代码之前,我也写过很多其它方式
dbfox
2015-11-22 20:20:31 +08:00
@msg7086
不拼接 sql 你们怎么写?
msg7086
2015-11-23 00:07:16 +08:00
@dbfox 用关系代数啊。我相信这么多年了.net 应该有很多基于关系代数的库了吧。
msg7086
2015-11-23 08:57:15 +08:00
用 Ruby 给你写了一个简单的例子,基于 Rails 的。

https://gist.github.com/msg7086/60e806bcccc00a49ecf4

我不敢说我的代码是可维护性好的代码,但是至少比你的代码要可维护得多。

比如说 Ruby 这边建议每个方法不应该超过 10 行,否则可维护性就会大大降低。我这边主函数将近 40 行,很明显的维护性就差很多。很多逻辑还可以抽离出来,使得结构更清晰。至于你这 180 行的函数我就不多说了,离讨论维护性这件事都差得很远。

读你的代码,首先第一个问题就是不知道这个函数到底接受哪些参数。(也就是你说的,连 IDE 都猜不透你函数到底接受什么东西。)这就意味着,一,新人要用你代码的时候,完全不知道该怎么用;二,你自己参数如果写错一个字母,你根本发现不了。等出了错你就慢慢 debug 吧。

其次是单函数结构。上面也说了,每个方法不应该超过 10 行。我们退一步讲,每个函数不应该超过 50 行好了。很多逻辑结构都可以抽出来做成单独的方法。看你这个 get_list ,应该是 Controller 方法吧,但是里面的很多逻辑是 Model 逻辑,应该放进 Model 类里。这样把函数拆开以后,还有一个好处就是做测试更方便了。
我不知道你的代码有多少自动化测试,不过我这边做开发,除非是做了就扔的项目,否则全都有做自动化测试覆盖。测试的代码量至少应该要达到项目代码量的一半甚至更多(通常是和项目代码量相同的级别)。这样项目在发布出去以后, bug 要少得多,哪怕用多一倍的时间去写测试,最后也会比不写测试要节约更多更多的时间。

最后就是拼接字符串,上面也说了不应该用字符串而应该用关系代数。用关系代数的话,可能会用到 ORM ,不过不用 ORM 应该也是可以做的,不知道 C#有没有可用的类库。但是用 C#不用 LINQ ,简直就是浪费了 C#在做 Web 上的最大优势之一了。(函数式, lambda ,延迟求值,匿名类,哪个不是超级好用的东西?)

你看我用了关系代数以后,根本不需要写一堆 AND ,不需要分 anywhere 和 orderby ,不需要考虑 WHERE 和 ORDER 的执行顺序,甚至连分页都不用我考虑了——因为有自动的分页插件,会自己往关系代数里注入合适的 LIMIT 子句。代码量轻松就掉了一半,开发速度更快了,而且出错的几率也下降了。

如上面很多人所说,程序员必然要经过很多个阶段,去反思自己的问题,才能向前走。你现在到达了封装参数发请求的阶段,自然觉得现在的方法是很不错。然而等你将来有机会接触了更好的方法,或者发现现有方法的各种坑了以后,才会知道更好的方法到底好在哪里。

把心态放平一些,然后多学习多看看吧。
dbfox
2015-11-23 09:26:15 +08:00
@jarlyyn

我查了下,你说的是 参数化查询的意思,我的 sql 是参数化查询,已经封装到 dbh
只是和 mysql 有区别,你们用的 ?,我这里用的 @ ,所以我这里不存在注入的问题
andwhere += " and categoryid=@cid ";







著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
作者:余天升
链接: http://www.zhihu.com/question/22953267/answer/23192081
来源:知乎

$stmt = $mysqli->prepare("DELETE FROM planet WHERE name = ?");
$stmt->bind_param('s', "earth");
$stmt->execute();



@msg7086

我真的不明白拼接 sql 怎么了?不拼接怎么写?
dbfox
2015-11-23 09:31:57 +08:00
@msg7086

是的,要把参数写的很详细

关系代数,是什么,我得去看看,.net 中似乎没这个东西,

linq 还是算了吧,从 linq to sql 到 linq to entity 都用过,不好用,深有体会
msg7086
2015-11-23 09:36:58 +08:00
LINQ 就是关系代数的一种实现。

PS: 我知道 LINQ to SQL 很难用。归根结底是因为 C#是一个比较静态的语言,不像 Ruby 那样可以玩各种奇技淫巧。
dbfox
2015-11-23 09:38:05 +08:00
@xujif

linq ef linq to sql 这些东西都不好用,不用它也是有原因的
xujif
2015-11-23 11:19:26 +08:00
@dbfox 虽然不用 c#好多年,建议能用强类型表示的还是用强类型,包括 linq ,能在编译期发现的问题就不要留到运行期。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/237257

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX