程序的账套模块,有一个账套间相互复制数据的功能,有几个表需要实现这个功能。这些表有共有属性:User_ID和Count_Set_ID。为了节省代码,我用一个接口规范了这几个类,其中接口包含上面两个属性。
数据的操作是在Linq To Sql的基础上实现的。所以操作大对象是DataClasses1DataContext db,自对象是db.Table.
具体的操作是,针对表一,有两个key,UserID+CountSetID。首先需要查询旧CountSetID下的所有数据,然后修改其CountSetID为目标ID,最后全部插入到数据库,完成。
扩展功能:在复制数据之前,可能要先删除目标ID下的所有数据。
void CopyCountSetSub(System.Data.Linq.Table data, int sourceID, int targetID, bool deleteB4Copy) where T : class, ICountSet{ if (deleteB4Copy)//删除旧数据 { var oldData = data.Where(x => x.User_ID == UserID && x.Count_Set_ID == targetID); data.DeleteAllOnSubmit(oldData); } var targetData = data.Where(x => x.User_ID == UserID && x.Count_Set_ID == sourceID).ToList(); targetData.ForEach(x => { T newX = (T)System.Activator.CreateInstance(typeof(T), x);//利用反射取得带参数的构造函数 newX.Count_Set_ID = targetID; data.InsertOnSubmit(newX); });}
上面的方法的参数:System.Data.Linq.Table<T> data将整个数据库映射对象传递过来。nt sourceID是源账套ID,int targetID是目标账套ID,bool deleteB4Copy则表示是否在复制前删除。
where T : class, ICountSet。约束此泛型方法的类型。其必须是类,必须继承自接口ICountSet。继承接口的作用是为了在方法中调用x.User_ID和x.Count_Set_ID。
方法的内容逻辑很明确:首先判断执行删除,然后赋值旧数据,在旧数据的基础上生成新数据,然后插入数据库。
这里有一个扩展,泛型类型的带一个参数的构造函数。本来泛型约束中有new(),如果where 后面约束了new(),可以这么做: T newOne = new T();使用前提是T必须有无参数的构造函数。而在这里,我们需要 T newOne = new T(x);没有new(T)的约束,直接这么敲代码,肯定得错,在这个泛型方法里面,不能判断T是否有这么一个构造函数。最后值得用反射来获得T的带参数的构造函数T newX = (T)System.Activator.CreateInstance(typeof(T), x); 传入x作为参数,创建一个实例并强制转换成类型T。随后修改newX的Count_Set_ID的值,然后插入数据库即即刻。
本片重点:泛型的使用;泛型的约束where,包括new(),class,Iinterface等;反射获取类型的带参数的构造函数并创建实例。
转载请注明出处: