倾分求Ado.net三层架构中,大字段的优雅处理方法

时间:2021-03-05 05:24:51
举例
数据库有一个Article表,其中有一个content字段是text类型的大字段
Ado.net三层架构中Model层中有一个实体ArticleModel对应Article表
DAL层有一个GetModelList方法,返回List<ArticleModel>,也就是完整的ArticleModel实体List
UI层有一个文章列表,列表中不需要用到content字段,如果还是用DAL层中的GetModelList方法,返回完整的ArticleModel实体List,肯定是不合适的,那么对于content这样的大字段要怎么处理呢

为UI层的文章列表专门作个实体类或写个GetModelListXXX()方法只填充需要字段这类的方式不考虑
一个朦胧的想法是利用Model里的Content属性作文章,写个类似延时加载的代码

因为现有系统框架限制,讨论仅限制ado.net三层,不讨论ORM

14 个解决方案

#1


不需要过度设计,因为就像你说地list<T>并不需要知道内容(当然根据需要他也许会给100-200字地简单说明,这个你另外搞)

所以正常情况只有单个T需要知道大字段内容

所以你只需写 getSingle<T>方法在里面填充大字段

#2


用事实说话,成熟的ORM性能不是瓶颈,灵活性不是问题:EF5.0、PDF.NET5.0、Dapper
http://my.oschina.net/lichaoqiang/blog/202249
这篇文章有讲到Content的问题,但探讨的是ORM,没讲ADO.NET架构下的解决方案

"记得我很早以前i(大概05年以前),刚听到ORM这个词的时候,就听到有人在说ORM性能不高,要求性能的地方都是直接SQL的,后来谈论ORM的人越来越多的时候,我也去关注了下,偶然间发现,尼玛,一个文章表的实体类,居然查询的时候把Content(内容)字段也查询出来了,这要是我查询个文章列表,这些内容字段不仅多余,而且严重影响性能,为啥不能只查询我需要的字段到ORM?自此对ORM没有好感,潜心研究SQL去了,将SQL封装到一个XML文件程序再来调用,还可以在运行时修改,别提多爽了,ORM,一边去吧:)"

ADO.NET架构下Content一定有一个优雅的解决方案,既然要保持实体的完整性,又能保证性能,但如何作呢?

#3


你说不考虑ORM,其实你作的就是ORM的事情。不过是自己写了一个“土”的没有通用性的ORM。。

真要按你的思路的话,可以这样:
private string content;

public string Conent{
get{ if (content==null) content = DBHelper.GetContent("SELECT [CONTENT] FROM Table WHERE ID=" + ID);
return conten;}
set {content=value;}
}

写个GetModelListXXX()方法只填充需要字段这类的方式不考虑, 这怎么可能做得到呢?只能在GetList里不能包含Content字段,所有ORM都应该是这么做的。

#4


引用 3 楼 bwangel 的回复:
你说不考虑ORM,其实你作的就是ORM的事情。不过是自己写了一个“土”的没有通用性的ORM。。

真要按你的思路的话,可以这样:
private string content;

public string Conent{
get{ if (content==null) content = DBHelper.GetContent("SELECT [CONTENT] FROM Table WHERE ID=" + ID);
return conten;}
set {content=value;}
}

写个GetModelListXXX()方法只填充需要字段这类的方式不考虑, 这怎么可能做得到呢?只能在GetList里不能包含Content字段,所有ORM都应该是这么做的。


get{ if (content==null) content = DBHelper.GetContent("SELECT [CONTENT] FROM Table WHERE ID=" + ID);
return conten;}
我想的大概就是这样的效果,这有什么不妥吗

另外你说
“写个GetModelListXXX()方法只填充需要字段这类的方式不考虑, 这怎么可能做得到呢?只能在GetList里不能包含Content字段,所有ORM都应该是这么做的。”
这不太明白你的意思

#5


很妥么,一点都不妥,你自己也说了list<T>其实不需要他,也不访问他

single<T>才要他,那么single<T>里面居然要访问2次数据库才能得到信息,你以为合适么

而且,如果你外面一个不靠谱的调用者,在list<T>里面去访问了他,好吧如果有1000条T,你这里要总共要访问1001次数据库,你很妥么???(你也不能保证人家不误用是吧)

ps:你还是受博客园地影响过大,其实在csdn这边俺们一直都说地是所谓model不是从一而终地,场景不同用处不同,本来就不是一个model打通关地搞法

#6


我以前玩过这方面,我也注意到如果碰上大字段类型,这样的操作完全不合适的,不过只针对一条数据,影响不大,不过当时我的项目大字段都是比较大的,小的大概5m,大的有几百m,这样的情况下,就显得不合适了,我就再建了一个不读取大字段的model,不过楼主你的情况 ,文章能有多大?不影响的,或者说,影响非常小,不必纠结这些。

#7


引用 4 楼 X_Craft 的回复:
Quote: 引用 3 楼 bwangel 的回复:

你说不考虑ORM,其实你作的就是ORM的事情。不过是自己写了一个“土”的没有通用性的ORM。。

真要按你的思路的话,可以这样:
private string content;

public string Conent{
get{ if (content==null) content = DBHelper.GetContent("SELECT [CONTENT] FROM Table WHERE ID=" + ID);
return conten;}
set {content=value;}
}

写个GetModelListXXX()方法只填充需要字段这类的方式不考虑, 这怎么可能做得到呢?只能在GetList里不能包含Content字段,所有ORM都应该是这么做的。


get{ if (content==null) content = DBHelper.GetContent("SELECT [CONTENT] FROM Table WHERE ID=" + ID);
return conten;}
我想的大概就是这样的效果,这有什么不妥吗

另外你说
“写个GetModelListXXX()方法只填充需要字段这类的方式不考虑, 这怎么可能做得到呢?只能在GetList里不能包含Content字段,所有ORM都应该是这么做的。”
这不太明白你的意思

写个GetModelListXXX()方法只填充需要字段这类的方式不考虑,这是你贴子的原话。
我的意思是,你的GetList只能填充需要字段。SELECT * 肯定是不行的。

一个方法访问二次数据库这没什么不妥。本来延迟加载就要多跑一次数据库。
只要访问次数保证是O(x)(x是常数)而不是O(n)或O(n2)就行了。

#8


引用 7 楼 bwangel 的回复:
Quote: 引用 4 楼 X_Craft 的回复:

Quote: 引用 3 楼 bwangel 的回复:

你说不考虑ORM,其实你作的就是ORM的事情。不过是自己写了一个“土”的没有通用性的ORM。。

真要按你的思路的话,可以这样:
private string content;

public string Conent{
get{ if (content==null) content = DBHelper.GetContent("SELECT [CONTENT] FROM Table WHERE ID=" + ID);
return conten;}
set {content=value;}
}

写个GetModelListXXX()方法只填充需要字段这类的方式不考虑, 这怎么可能做得到呢?只能在GetList里不能包含Content字段,所有ORM都应该是这么做的。


get{ if (content==null) content = DBHelper.GetContent("SELECT [CONTENT] FROM Table WHERE ID=" + ID);
return conten;}
我想的大概就是这样的效果,这有什么不妥吗

另外你说
“写个GetModelListXXX()方法只填充需要字段这类的方式不考虑, 这怎么可能做得到呢?只能在GetList里不能包含Content字段,所有ORM都应该是这么做的。”
这不太明白你的意思

写个GetModelListXXX()方法只填充需要字段这类的方式不考虑,这是你贴子的原话。
我的意思是,你的GetList只能填充需要字段。SELECT * 肯定是不行的。

一个方法访问二次数据库这没什么不妥。本来延迟加载就要多跑一次数据库。
只要访问次数保证是O(x)(x是常数)而不是O(n)或O(n2)就行了。


get{ if (content==null) content = DBHelper.GetContent("SELECT [CONTENT] FROM Table WHERE ID=" + ID);
通过这种方式,GetModelList()肯定是需要修改,忽略Content字段的填充。

#9


引用 5 楼 wanghui0380 的回复:
很妥么,一点都不妥,你自己也说了list<T>其实不需要他,也不访问他

single<T>才要他,那么single<T>里面居然要访问2次数据库才能得到信息,你以为合适么

而且,如果你外面一个不靠谱的调用者,在list<T>里面去访问了他,好吧如果有1000条T,你这里要总共要访问1001次数据库,你很妥么???(你也不能保证人家不误用是吧)

ps:你还是受博客园地影响过大,其实在csdn这边俺们一直都说地是所谓model不是从一而终地,场景不同用处不同,本来就不是一个model打通关地搞法


你说的我有点不太明白,你的意思是建个表专门放Content这样的大字段,还是建个实体专门放Content这样的大字段?
具体要怎么实体呢,能上段Demo代码吗

#10


这里个人发表下ORM的一些看法
1、ORM  当然个人只用了EF  所以只说EF  有个延迟查询  实际上符合你的要求
2、你说ORM默认查询所有 这个也可以解决 最后select new{} 你需要的字段即可
相信这些特色功能应该可以满足LZ的需求了吧  其实ORM还是蛮好用的  效率的话  如果不是像银行那么多客户的话  个人感觉应该不会有太大影响 不过个人没有做过大数据和并发  可能不是很清楚  以上仅为建议

#11


引用 10 楼 oLanJieKou 的回复:
这里个人发表下ORM的一些看法
1、ORM  当然个人只用了EF  所以只说EF  有个延迟查询  实际上符合你的要求
2、你说ORM默认查询所有 这个也可以解决 最后select new{} 你需要的字段即可
相信这些特色功能应该可以满足LZ的需求了吧  其实ORM还是蛮好用的  效率的话  如果不是像银行那么多客户的话  个人感觉应该不会有太大影响 不过个人没有做过大数据和并发  可能不是很清楚  以上仅为建议

主要是现在的需求没法用ORM,所以倒回去用ado.net,用的时候就发现这个大字段处理的问题,所以想以ORM的思想来实体,但又不确定怎么作合适

#12


引用 11 楼 X_Craft 的回复:
Quote: 引用 10 楼 oLanJieKou 的回复:

这里个人发表下ORM的一些看法
1、ORM  当然个人只用了EF  所以只说EF  有个延迟查询  实际上符合你的要求
2、你说ORM默认查询所有 这个也可以解决 最后select new{} 你需要的字段即可
相信这些特色功能应该可以满足LZ的需求了吧  其实ORM还是蛮好用的  效率的话  如果不是像银行那么多客户的话  个人感觉应该不会有太大影响 不过个人没有做过大数据和并发  可能不是很清楚  以上仅为建议

主要是现在的需求没法用ORM,所以倒回去用ado.net,用的时候就发现这个大字段处理的问题,所以想以ORM的思想来实体,但又不确定怎么作合适


如果你想自己去封装类似于EF的框架(即使是你现在想要的打字段处理,也就是延迟查询),那你要清楚EF的原理  要对他很熟悉   框架我也只是会用。。。唉   因为个人觉得站在巨人的肩膀上摘的苹果未必不甜   不然就辜负了前辈们的心血   那这个LZ还是慢慢思考吧   然后建议在做项目的时候首先要做好选择  不然就会像现在这样    自己进退两难

#13


引用 3 楼 bwangel 的回复:
你说不考虑ORM,其实你作的就是ORM的事情。不过是自己写了一个“土”的没有通用性的ORM。。

真要按你的思路的话,可以这样:
private string content;

public string Conent{
get{ if (content==null) content = DBHelper.GetContent("SELECT [CONTENT] FROM Table WHERE ID=" + ID);
return conten;}
set {content=value;}
}

写个GetModelListXXX()方法只填充需要字段这类的方式不考虑, 这怎么可能做得到呢?只能在GetList里不能包含Content字段,所有ORM都应该是这么做的。


我的实现没有用DBHelper,而是直接在Model实体中调用DAL层的方法:


        private bool _contentIsLoaded = false;
        public string Content
        {
            get
            {
                if (!_contentIsLoaded)
                {
                    value = ArticleService.GetContent(ID);
                    _contentIsLoaded = true;
                }
                return value;
            }
        }


很不幸,因为DAL项目已经引用Model项目了,如果Model中再引用DAL会被VS提示循环引用,所以以上想法无法实现

难道只能在Model中直接调用DBHelper了吗?
再求ADO.NET三层中大字段数据处理的好思路!

#14


难道你不会单独写一个方法

select 你要的字段,没有content from xxoo 

然后返回datatable吗?

既然是list肯定是绑定了 返回list跟datatable有什么关系...

就是一个小小的业务而已.单独写又不会死人,否则BLL是干吗用的?

真不知道你在操什么心...

#1


不需要过度设计,因为就像你说地list<T>并不需要知道内容(当然根据需要他也许会给100-200字地简单说明,这个你另外搞)

所以正常情况只有单个T需要知道大字段内容

所以你只需写 getSingle<T>方法在里面填充大字段

#2


用事实说话,成熟的ORM性能不是瓶颈,灵活性不是问题:EF5.0、PDF.NET5.0、Dapper
http://my.oschina.net/lichaoqiang/blog/202249
这篇文章有讲到Content的问题,但探讨的是ORM,没讲ADO.NET架构下的解决方案

"记得我很早以前i(大概05年以前),刚听到ORM这个词的时候,就听到有人在说ORM性能不高,要求性能的地方都是直接SQL的,后来谈论ORM的人越来越多的时候,我也去关注了下,偶然间发现,尼玛,一个文章表的实体类,居然查询的时候把Content(内容)字段也查询出来了,这要是我查询个文章列表,这些内容字段不仅多余,而且严重影响性能,为啥不能只查询我需要的字段到ORM?自此对ORM没有好感,潜心研究SQL去了,将SQL封装到一个XML文件程序再来调用,还可以在运行时修改,别提多爽了,ORM,一边去吧:)"

ADO.NET架构下Content一定有一个优雅的解决方案,既然要保持实体的完整性,又能保证性能,但如何作呢?

#3


你说不考虑ORM,其实你作的就是ORM的事情。不过是自己写了一个“土”的没有通用性的ORM。。

真要按你的思路的话,可以这样:
private string content;

public string Conent{
get{ if (content==null) content = DBHelper.GetContent("SELECT [CONTENT] FROM Table WHERE ID=" + ID);
return conten;}
set {content=value;}
}

写个GetModelListXXX()方法只填充需要字段这类的方式不考虑, 这怎么可能做得到呢?只能在GetList里不能包含Content字段,所有ORM都应该是这么做的。

#4


引用 3 楼 bwangel 的回复:
你说不考虑ORM,其实你作的就是ORM的事情。不过是自己写了一个“土”的没有通用性的ORM。。

真要按你的思路的话,可以这样:
private string content;

public string Conent{
get{ if (content==null) content = DBHelper.GetContent("SELECT [CONTENT] FROM Table WHERE ID=" + ID);
return conten;}
set {content=value;}
}

写个GetModelListXXX()方法只填充需要字段这类的方式不考虑, 这怎么可能做得到呢?只能在GetList里不能包含Content字段,所有ORM都应该是这么做的。


get{ if (content==null) content = DBHelper.GetContent("SELECT [CONTENT] FROM Table WHERE ID=" + ID);
return conten;}
我想的大概就是这样的效果,这有什么不妥吗

另外你说
“写个GetModelListXXX()方法只填充需要字段这类的方式不考虑, 这怎么可能做得到呢?只能在GetList里不能包含Content字段,所有ORM都应该是这么做的。”
这不太明白你的意思

#5


很妥么,一点都不妥,你自己也说了list<T>其实不需要他,也不访问他

single<T>才要他,那么single<T>里面居然要访问2次数据库才能得到信息,你以为合适么

而且,如果你外面一个不靠谱的调用者,在list<T>里面去访问了他,好吧如果有1000条T,你这里要总共要访问1001次数据库,你很妥么???(你也不能保证人家不误用是吧)

ps:你还是受博客园地影响过大,其实在csdn这边俺们一直都说地是所谓model不是从一而终地,场景不同用处不同,本来就不是一个model打通关地搞法

#6


我以前玩过这方面,我也注意到如果碰上大字段类型,这样的操作完全不合适的,不过只针对一条数据,影响不大,不过当时我的项目大字段都是比较大的,小的大概5m,大的有几百m,这样的情况下,就显得不合适了,我就再建了一个不读取大字段的model,不过楼主你的情况 ,文章能有多大?不影响的,或者说,影响非常小,不必纠结这些。

#7


引用 4 楼 X_Craft 的回复:
Quote: 引用 3 楼 bwangel 的回复:

你说不考虑ORM,其实你作的就是ORM的事情。不过是自己写了一个“土”的没有通用性的ORM。。

真要按你的思路的话,可以这样:
private string content;

public string Conent{
get{ if (content==null) content = DBHelper.GetContent("SELECT [CONTENT] FROM Table WHERE ID=" + ID);
return conten;}
set {content=value;}
}

写个GetModelListXXX()方法只填充需要字段这类的方式不考虑, 这怎么可能做得到呢?只能在GetList里不能包含Content字段,所有ORM都应该是这么做的。


get{ if (content==null) content = DBHelper.GetContent("SELECT [CONTENT] FROM Table WHERE ID=" + ID);
return conten;}
我想的大概就是这样的效果,这有什么不妥吗

另外你说
“写个GetModelListXXX()方法只填充需要字段这类的方式不考虑, 这怎么可能做得到呢?只能在GetList里不能包含Content字段,所有ORM都应该是这么做的。”
这不太明白你的意思

写个GetModelListXXX()方法只填充需要字段这类的方式不考虑,这是你贴子的原话。
我的意思是,你的GetList只能填充需要字段。SELECT * 肯定是不行的。

一个方法访问二次数据库这没什么不妥。本来延迟加载就要多跑一次数据库。
只要访问次数保证是O(x)(x是常数)而不是O(n)或O(n2)就行了。

#8


引用 7 楼 bwangel 的回复:
Quote: 引用 4 楼 X_Craft 的回复:

Quote: 引用 3 楼 bwangel 的回复:

你说不考虑ORM,其实你作的就是ORM的事情。不过是自己写了一个“土”的没有通用性的ORM。。

真要按你的思路的话,可以这样:
private string content;

public string Conent{
get{ if (content==null) content = DBHelper.GetContent("SELECT [CONTENT] FROM Table WHERE ID=" + ID);
return conten;}
set {content=value;}
}

写个GetModelListXXX()方法只填充需要字段这类的方式不考虑, 这怎么可能做得到呢?只能在GetList里不能包含Content字段,所有ORM都应该是这么做的。


get{ if (content==null) content = DBHelper.GetContent("SELECT [CONTENT] FROM Table WHERE ID=" + ID);
return conten;}
我想的大概就是这样的效果,这有什么不妥吗

另外你说
“写个GetModelListXXX()方法只填充需要字段这类的方式不考虑, 这怎么可能做得到呢?只能在GetList里不能包含Content字段,所有ORM都应该是这么做的。”
这不太明白你的意思

写个GetModelListXXX()方法只填充需要字段这类的方式不考虑,这是你贴子的原话。
我的意思是,你的GetList只能填充需要字段。SELECT * 肯定是不行的。

一个方法访问二次数据库这没什么不妥。本来延迟加载就要多跑一次数据库。
只要访问次数保证是O(x)(x是常数)而不是O(n)或O(n2)就行了。


get{ if (content==null) content = DBHelper.GetContent("SELECT [CONTENT] FROM Table WHERE ID=" + ID);
通过这种方式,GetModelList()肯定是需要修改,忽略Content字段的填充。

#9


引用 5 楼 wanghui0380 的回复:
很妥么,一点都不妥,你自己也说了list<T>其实不需要他,也不访问他

single<T>才要他,那么single<T>里面居然要访问2次数据库才能得到信息,你以为合适么

而且,如果你外面一个不靠谱的调用者,在list<T>里面去访问了他,好吧如果有1000条T,你这里要总共要访问1001次数据库,你很妥么???(你也不能保证人家不误用是吧)

ps:你还是受博客园地影响过大,其实在csdn这边俺们一直都说地是所谓model不是从一而终地,场景不同用处不同,本来就不是一个model打通关地搞法


你说的我有点不太明白,你的意思是建个表专门放Content这样的大字段,还是建个实体专门放Content这样的大字段?
具体要怎么实体呢,能上段Demo代码吗

#10


这里个人发表下ORM的一些看法
1、ORM  当然个人只用了EF  所以只说EF  有个延迟查询  实际上符合你的要求
2、你说ORM默认查询所有 这个也可以解决 最后select new{} 你需要的字段即可
相信这些特色功能应该可以满足LZ的需求了吧  其实ORM还是蛮好用的  效率的话  如果不是像银行那么多客户的话  个人感觉应该不会有太大影响 不过个人没有做过大数据和并发  可能不是很清楚  以上仅为建议

#11


引用 10 楼 oLanJieKou 的回复:
这里个人发表下ORM的一些看法
1、ORM  当然个人只用了EF  所以只说EF  有个延迟查询  实际上符合你的要求
2、你说ORM默认查询所有 这个也可以解决 最后select new{} 你需要的字段即可
相信这些特色功能应该可以满足LZ的需求了吧  其实ORM还是蛮好用的  效率的话  如果不是像银行那么多客户的话  个人感觉应该不会有太大影响 不过个人没有做过大数据和并发  可能不是很清楚  以上仅为建议

主要是现在的需求没法用ORM,所以倒回去用ado.net,用的时候就发现这个大字段处理的问题,所以想以ORM的思想来实体,但又不确定怎么作合适

#12


引用 11 楼 X_Craft 的回复:
Quote: 引用 10 楼 oLanJieKou 的回复:

这里个人发表下ORM的一些看法
1、ORM  当然个人只用了EF  所以只说EF  有个延迟查询  实际上符合你的要求
2、你说ORM默认查询所有 这个也可以解决 最后select new{} 你需要的字段即可
相信这些特色功能应该可以满足LZ的需求了吧  其实ORM还是蛮好用的  效率的话  如果不是像银行那么多客户的话  个人感觉应该不会有太大影响 不过个人没有做过大数据和并发  可能不是很清楚  以上仅为建议

主要是现在的需求没法用ORM,所以倒回去用ado.net,用的时候就发现这个大字段处理的问题,所以想以ORM的思想来实体,但又不确定怎么作合适


如果你想自己去封装类似于EF的框架(即使是你现在想要的打字段处理,也就是延迟查询),那你要清楚EF的原理  要对他很熟悉   框架我也只是会用。。。唉   因为个人觉得站在巨人的肩膀上摘的苹果未必不甜   不然就辜负了前辈们的心血   那这个LZ还是慢慢思考吧   然后建议在做项目的时候首先要做好选择  不然就会像现在这样    自己进退两难

#13


引用 3 楼 bwangel 的回复:
你说不考虑ORM,其实你作的就是ORM的事情。不过是自己写了一个“土”的没有通用性的ORM。。

真要按你的思路的话,可以这样:
private string content;

public string Conent{
get{ if (content==null) content = DBHelper.GetContent("SELECT [CONTENT] FROM Table WHERE ID=" + ID);
return conten;}
set {content=value;}
}

写个GetModelListXXX()方法只填充需要字段这类的方式不考虑, 这怎么可能做得到呢?只能在GetList里不能包含Content字段,所有ORM都应该是这么做的。


我的实现没有用DBHelper,而是直接在Model实体中调用DAL层的方法:


        private bool _contentIsLoaded = false;
        public string Content
        {
            get
            {
                if (!_contentIsLoaded)
                {
                    value = ArticleService.GetContent(ID);
                    _contentIsLoaded = true;
                }
                return value;
            }
        }


很不幸,因为DAL项目已经引用Model项目了,如果Model中再引用DAL会被VS提示循环引用,所以以上想法无法实现

难道只能在Model中直接调用DBHelper了吗?
再求ADO.NET三层中大字段数据处理的好思路!

#14


难道你不会单独写一个方法

select 你要的字段,没有content from xxoo 

然后返回datatable吗?

既然是list肯定是绑定了 返回list跟datatable有什么关系...

就是一个小小的业务而已.单独写又不会死人,否则BLL是干吗用的?

真不知道你在操什么心...