首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > asp.net >

共享小弟我的实体类设计方法,请大家多多指教

2012-02-17 
共享我的实体类设计方法,请大家多多指教。C# code/* * 我是由ASP转C#的,写C#也有两三年了,也作过几个小项目

共享我的实体类设计方法,请大家多多指教。

C# code
/* * 我是由ASP转C#的,写C#也有两三年了,也作过几个小项目,因为一直都是一个人开发,所以许多东西都是google或是自己琢磨的,基本上是举步艰难,不过还算是乐在其中吧。 * 因为是作的项目比较小,所以实体类基本上是一个核心部份了,所以对这部份东西比较上心,但是,没人交流,故,也不知道到底怎么样。 * 在这里我把我实现实体类的方式共享出来,大家也请指点一下。 *  * 简单说一下原理: * 把IDataReader转成Dictionary<string, object>,然后在读取时再赋值到相应的字段属性内。 * 而关联表通过交流Dictionary<string, object>来实现关联表操作 *  * 现在头疼的地方就是getParameter()方法,用这个方法我可以把简单的添加修改删除代码抽象出来,不用每个类去专门写一段添加修改删除的操作 * 头疼的是,修改时也需要把整个实体类的所有字段都读一遍,这明显就是浪费了。 *  * 我本身预想有两种方法,一是用switch,或是If,或是干脆再来一个方法专门给修改用。但是一直没有作出选择,不知道还有什么更好的办法处理不。 *///实体类的基类public abstract class RecordBase{    //记录IDataReader数据集内的数据    //此处的Dictionary<>,实际应用时我用的是一个object[]数据来作记录,获取字段值时才将数组转换成Dictionary<>来使用。这样实体类才实现能序列化。    private Dictionary<string, object> _recordValue;    protected Dictionary<string, object> recordValue    {        get { if (_recordValue == null) { _recordValue = new Dictionary<string, object>(); } return _recordValue; }        set { _recordValue = value; }    }    //接收IDataReader的数据    public RecordBase(IDataReader dr)    {        this.recordValue = new Dictionary<string, object>(dr.FieldCount);        for (int x = 0; x < dr.FieldCount; x++)        {            this.recordValue.Add(dr.GetName(x), dr.GetValue(x));        }    }    //作为关联数据表    public RecordBase(Dictionary<string, object> recordValue)    {        this.recordValue = recordValue;    }    //获取字段值,之所以作成一个方法单独处理只是不想把try放得到处都是而以。    private object getValue(string field)    {        object value = null;        /*         * 这里之所有用try而不用recordValue.ContainsKey来判断字段是否存在,         * 是因为字段不存在这种错误是不应该出现的,如果出现那就是查询句或是别的地方有错。         * 所以不需要用recordValue.ContainsKey来跳出找不到字段的错误,         * 而用try来抛出错误的话,可以更好的提示程序员出错是什么原因。         */        try        {                        //字段值为DBNull时返回null,让getFieldValue作适当的处理。            if (!(recordValue[field] is DBNull)) { value = recordValue[field]; }        }        catch (Exception e) { throw new Exception(string.Format("找不以字段{0}", name)); }        return value;    }    #region 获取字段值    //获取字段数据类型为 decimal 的字段值    private decimal getFieldValue(ref decimal? properties, string fieldName)    {        if (!properties.HasValue) { properties = (decimal)(this.getValue(fieldName) ?? 0m); }        return properties.GetValueOrDefault();    }    //获取字段数据类型为 string 的字段值    protected string getFieldValue(ref string properties, string fieldName)    {        if (properties == null) { properties = (getValue(fieldName) ?? "").ToString(); }        return properties;    }    /* 还有其它数据类型的字段提取方式这里就不作出来了,反正都差不多的 */    #endregion}//实体类 添加修改删除操作 接口public interface IRecordModify{    Dictionary<string, object> getParameter();//获取实体类的字段与字段值    string getTableName();//因为Modify用的是泛型操作,所以需要获取列名的方法    decimal Id { get; set; }//因为添加新记录时需要获取新记录的Id号}//Record数据表的实体类public class Record : RecordBase, IRecordModify{    private decimal? _id;    private string _name;    public Record() { }    public Record(IDataReader dr) : base(dr) { }    public Record(Dictionary<string, object> recordValue) : base(recordValue) { }    #region 字段    public decimal Id    {        get { return this.getFieldValue(ref _id, FieldName.Id); }        set { _id = value; }    }    public string Name    {        get { return this.getFieldValue(ref _name, FieldName.Name); }    }    #endregion    #region 关系表    [NonSerialized]    private Relations _relations;    public Relations Relations    {        get        {            if (_relations == null) { _relations = new Relations(this.recordValue); }        }    }    #endregion    //表名    public const string TableName = "Record";    //字段列表    public class FieldName    {        public const string Id = "id";        public const string Name = "name";    }    #region IRecordModify 成员    Dictionary<string, object> IRecordModify.getParameter()    {        Dictionary<string, object> dList = new Dictionary<string, object>();        dList.Add(FieldName.Id, this.Id);        dList.Add(FieldName.Name, this.Name);        return dList;    }    string IRecordModify.getTableName()    {        return TableName;    }    #endregion}//与数据表Record有关联的Relations数据表实体类public class Relations : RecordBase {    private decimal? _Id;    public Relations() { }    public Relations(IDataReader dr) : base(dr) { }    public Relations(Dictionary<string, object> recordValue) : base(recordValue) { }    public const string TableName = "Relations";    public class FieldName    {        public const string Id = "id";    }} 



结贴后我会在我的blog里http://blog.csdn.net/oyiboy再开个贴,欢迎大家到时去讨论

[解决办法]
先顶再看.
[解决办法]
写的不错,数据库字段用属性表示。
添加修改删除通过接口操作相关数据库,实现数据维护.

[解决办法]
up
[解决办法]
学习了。。顶
[解决办法]
先看看.
[解决办法]
Up
[解决办法]
写的不错,Up
[解决办法]
学习!!!
[解决办法]
LZ的分享精神值得学习!
[解决办法]

[解决办法]
先顶在看
[解决办法]
不错的!
[解决办法]
受PETSHOP的影响太大了

现在才知道还能这么写实体类。。。。。。

受教!!受教!!!
[解决办法]
顶个
[解决办法]
学习了 UP
[解决办法]
不错,学习!
[解决办法]
看的不咋明白 还要多看看
[解决办法]
不错,学习了..........
[解决办法]
没看太明白,楼主解释下!
[解决办法]
太绕了。

还是取代不了代码生成器生成的代码。

getValue 用字段名取值,性能不如微软的用字段索引取值的快。

而且返回的是object,大部分情况下还得再转化一下。
[解决办法]
不管怎样
 顶一下
[解决办法]
楼主写的不错,先顶一下
[解决办法]
不错,先收藏了
[解决办法]
我有个疑问, Dictionary<>类好像并没有实现IList 接口,这样你的value是不能直接绑定的,楼住是怎么处理这块的呢?
[解决办法]
不错。学习
[解决办法]
似乎从来没这么写过……学习下……
[解决办法]
回帖是一种美德!每天回帖即可获得 10 分可用分!
[解决办法]
先顶再看
[解决办法]
挺不错的.
[解决办法]
public class FieldName

如果说这个类仅仅用于保存Field名称.那么,是不是可以用来记录字段类型无论是用特性或是用属性

且先不论这个名称或是类型去从哪里得到.至少行到类型之后,可以调用IDataReader相应的重载来得到字段值



------解决方案--------------------


呵呵,多此一举的在 getvalue返回的是一个object 然后再由object 返回各个类型

你直接用getint,getstring,getdate之类的不就完了?

[解决办法]
uping
[解决办法]
学习
。。。。
[解决办法]
jf

[解决办法]
回帖是一种美德!每天回帖即可获得 10 分可用分!
[解决办法]
学习一下
[解决办法]
不错,先收藏了
[解决办法]
不错
[解决办法]
学习
[解决办法]
好啊。

[解决办法]
up
[解决办法]
学习!!
[解决办法]
收藏
[解决办法]
good!
[解决办法]
kankanm
[解决办法]
顶下
[解决办法]
对实体类进行封装, 不错呵!
支持一下
[解决办法]
看看你的类如何获得
Record r1 = new Record(sqldatareader);
这点大家都是这么做的
下面看一下,我用自动工具(codesmith)生成的类

 

C# code
using (SqlDataReader rdr = SqlHelper.ExecuteReader(SqlHelper.ConnectionStringLocalTransaction, CommandType.Text, SQL_GET_USERPRODUCT , parameters))            {                while (rdr.Read())                {                    product.ProductId = rdr.GetString(0);                    product.UserName = rdr.GetString(1);                    product.CompanyID = rdr.GetInt32(2);                    product.CategoryId = rdr.GetString(3);                    product.Name = rdr.GetString(4);                    product.Descn = rdr.GetString(5);                    product.Image = rdr.GetString(6);                    product.ImageSmall = rdr.GetString(7);                    product.Keyword = rdr.GetString(8);                    product.PlaceOfOrigin = rdr.GetString(9);                    product.BrandName = rdr.GetString(10);                    product.Payment = rdr.GetString(11);                    product.UnitPrice = rdr.GetString(12);                    product.Packing = rdr.GetString(13);                    product.PaymentTerms = rdr.GetString(14);                    product.PaymentRemark = rdr.GetString(15);                    product.DeliveryTime = rdr.GetString(16);                    product.MinOrder = rdr.GetString(17);                    product.SupplyAbility = rdr.GetString(18);                    product.Certification = rdr.GetString(19);                    product.AddTime = rdr.GetDateTime(20);                    product.EditTime = rdr.GetDateTime(21);                    product.ProductState = rdr.GetInt32(22);                    product.Model = rdr.GetString(23);                    product.Currency = rdr.GetString(24);                    products.Add(product);                }            }
[解决办法]


上文表字段改变索引改变,类型改变,这点,是属实的,
但是应用中,很少在运行期问去更改表结构

如果的确存在字段不确定的时候,我会采用列转行的形式

上文中不存在装箱.如果你仅仅你认为 object getvalue,那么,
所有的类型均可以用object表示,你的意思可以不可以均理解为这类转换均不需要装箱


不过在转换方面你是我认识中最能转的了

比如这一段

product.ProductId = rdr.GetString(0);

你的想法就很奇特,

非要去得到一个string fieldname
再根据fieldname去查到fieldindex,再去根据fieldindex去getstring或index

 public string getFieldValue(string field, IDataReader dr, int number)
 {
return dr.GetString(number);
}





[解决办法]
所以你写出这么能绕的程序我能理解..
何况程序员多多少少有一点偏执,意见归意见,不能接受也不多讲

你贴上来的程序好像也不是很合语法
 if (!properties.HasValue) { properties = (decimal)(this.getValue(fieldName) ?? 0m); }

this.getValue(fieldName) ?? 0m

像三目吧,又不太像..
我就没细看,至于存到哪里去了,我确实是不知道

[解决办法]
学习。
[解决办法]
不错,学习一下
[解决办法]
UP 慢慢看
[解决办法]
Mark...!!!

终于看到传说中的实体类了。
[解决办法]
up
[解决办法]
.
[解决办法]
事实上,我个人感觉不怎么样。

1 编译时,如果字段名称是AAA,结果写成了AAB,编译不出错。

2 编译时,使用这个实体类的人,时时需要关心,数据类型,有大量的拆箱的过去,如果类型错误,编译也不出错。

所以我感觉这样的实体类,分大大分散开发人员的注意力,而这些注意力应该被使用到业务逻辑处理上面的。

建议楼主看一下LINQ产生的实体类。


一家之言,不当之处,请开心一笑。


[解决办法]
有必要这么写吗?还真没这么写过实体类
[解决办法]
楼主有才,支持自学
[解决办法]
支持楼主!同样是个人开发,需要坚持和努力,学习!
[解决办法]
不错。。
写的有水平。。。
[解决办法]
有水平。。这样节约很多方法...赞一个 我一个同事也是这样写的..
 如果能做成模版就更好了.
[解决办法]
不错 人才~~!
[解决办法]
楼主
你是否觉得你的dictionary<string,object>是神来之笔吧
[解决办法]
我是用反射的。反正有缓存,也不怕慢
[解决办法]

实体类太长了
[解决办法]
其实大家并没有说你的方法不对,只有说有改良的余地,
就是绕来绕去的,把所有的类型先转为object,再还原为它的基类型

其实呢,对类型进行判别再调用相应的Get<类型>(索引)
 如getint16(i) getstring(i) getbyte(i)
在MSDN中是认同的这样的操作的
比如我们在MSDN中可以看到这样一段
http://msdn.microsoft.com/zh-cn/library/system.data.idatarecord.getfieldtype.aspx

通过指示要调用的强类型访问器,此信息可用于提高性能。(例如,使用 GetInt32 比使用 GetValue 快大约十倍。)


如果你想在运行时判定字段类型,有很多种方法,如反射


 private object getValue(string field)
{

Type t = this.GetType();
FieldInfo fi = t.GetField(fieldname, BindingFlags.NonPublic | BindingFlags.Instance);
if (fi.FieldType == typeof(string))
{
 //你的处理方法
}


else if (fi.FieldType == typeof(int))
{
}
object value = null;
/*
* 这里之所有用try而不用recordValue.ContainsKey来判断字段是否存在,
* 是因为字段不存在这种错误是不应该出现的,如果出现那就是查询句或是别的地方有错。
* 所以不需要用recordValue.ContainsKey来跳出找不到字段的错误,
* 而用try来抛出错误的话,可以更好的提示程序员出错是什么原因。
*/
try
{

//字段值为DBNull时返回null,让getFieldValue作适当的处理。
if (!(recordValue[field] is DBNull)) { value = recordValue[field]; }
}
catch (Exception e) { throw new Exception(string.Format("找不以字段{0}", name)); }
return value;
}

如果你认为上面的只有类型太少了,你还可以自定

[AttributeUsage(AttributeTargets.Field)]
public class FieldTypeAttribute :System.Attribute 
{
string fieldtype;
int length
public FieldTypeAttribute(string ft,int length)
{
this.fieldtype = ft;
this.length = length;
}
public string FieldType
{
get
{
return fieldtype;
}
}
public length
{
get{return this.length;}
}
}

//标记
[FieldType("nvarchar",80)]
private string productname ;


//获取信息
 Type t = this.GetType();
 FieldInfo fi = t.GetField(fieldname, BindingFlags.NonPublic | BindingFlags.Instance);
if (fi.IsDefined(typeof(FieldTypeAttribute), false))
{
 FieldTypeAttribute fta = fi.GetCustomAttributes(typeof(FieldTypeAttribute), false)[0] as FieldTypeAttribute;

//fta.FieldType
//fta.length

}


可以负责任的告诉你. 3.5中的实体类.也是采用特性来得到这些信息的



[解决办法]

探讨
引用:
事实上,我个人感觉不怎么样。

1 编译时,如果字段名称是AAA,结果写成了AAB,编译不出错。

2 编译时,使用这个实体类的人,时时需要关心,数据类型,有大量的拆箱的过去,如果类型错误,编译也不出错。

所以我感觉这样的实体类,分大大分散开发人员的注意力,而这些注意力应该被使用到业务逻辑处理上面的。

建议楼主看一下LINQ产生的实体类。


一家之言,不当之处,请开心…

[解决办法]
mark
[解决办法]
学习下
[解决办法]
up
[解决办法]
up
[解决办法]
用ORM工具吧.没必要这么累.
[解决办法]
其实,实体类的最大意义就在于:可以通过工具生成实体类(他人或自己写的工具)
对于表结构改变的而产生维护实体类的问题,完全可以通过工具重新覆盖一遍来解决。

另外,普遍的认识中,认为DataReader读取的速度比DataTable来得快(实际上,2.0以后的DataTable的性能大大提高了),但问题在于
1.DataReader中,数据格式为Object,当对字段属性赋值时,仍然需要大量的转换。
2.数据库字段中,除了Null之外,还存在空的情况。
由于需要大量转换,导致读取快的优点被大量抵消。

早期的时候,我处理数据也是使用DataReader来进行,后来发现,使用DataTable获取数据(2.0后),根本不比前者慢,而且由于得到的数据明确都是string类型,即使数据库中为NULL或空,都能够通过dt["xxx"].ToString()方式获得非空的""(空串),数据的判断由此变得单一。
改变取值方式之后,经过测试,两者之间的速度不相上下。

另外,ORM最大的问题在于如何处理关系类。很多工具使用了各式的方法来达成这个目的,但几乎都造成复杂度大大提高的后果。
但这个问题,如果通过对数据库表与字段严格的命名方式来解决,就变得非常的轻松愉快了。如果你设计实体类并不想变成一个公用的东西,而只是解决自己的问题在自己的项目或团队中使用,那么,我建议你使用对表设计的规范来解决。比如
asm_branch表
字段:brc_id
asm_user表
相关字段:usr_brc_id
如上:在我们的定义中,usr_brc_id字段中的后6位字母,即是关联到某个表主键为该6位字母的表(前提是所有的字段不可重名),在这种情况下,实现实体类的关联,轻而易举。


再有,对于增、删、改操作,当然可以使用某些接口或反射之类的方法来实现,代码会少很多,但同时性能也会降低很多。
如果你有自己的实体类生成器,那么,生成实体类根本就是不需要费心的事情,这种情况下,值得为了减少一点代码而牺牲性能吗?不需要,当表字段变化时,无非是再生成一次罢了。
[解决办法]
学习
------解决方案--------------------


学习。/////
[解决办法]
写的不错, 数据库字段用属性表示。 

热点排行