注意:

     1.本文中所提到的“实体”均为由LINQ TO SQL生成的(即.dbml)

     2.你需要了解LINQ TO SQL对表关联的实现方式,EntitySet 和 EntityRef

     也许你看到标题后,会觉得问题比较抽象,那么我举个实例来具体说明一下问题。

 

      在基于LINQ TO SQL的N层架构中,假如我们需要对一个实体进行更新,那么流程应是这样:

 

流程

 

BLL.GetModel(p=>p.id==1) --> 修改相应属性(字段)值 --> BLL.Update(Entity entity) --> DAL.Update(Entity entity) --> 更新成功

 

     此时,我们需要将这个实体从业务层(BLL)传递到数据访问层(DAL),当GetModel方法返回实体后会立即释放掉DataContext,然后到了执行DAL.Update(Entity entity)方法时又重新实例化一个DataContext来进行更新操作;可见被传递的实体是从第一个DataContext传递到另一个DataContext,在LINQ TO SQL中这种跨越不同DataContext操作时,需要先进行附加操作,也就是context.Entity.Attach(entity,true); 最后再context.SubmitChanges();

 

还是看看代码吧:

 

代码
class BLL
{
  
private readonly DAL dal = new DAL();
  
public LinqToSqlProvider.User GetModel(Expression<Func<LinqToSqlProvider.User, bool>> expression)
{
   dal.GetModel(expression);
}
  
public void Update(LinqToSqlProvider.User entity)
  {
     dal.Update(entity);
  }
}

class DAL
{
        
        
public LinqToSqlProvider.User GetModel(Expression<Func<LinqToSqlProvider.User, bool>> expression)
        {
            LinqToSqlProvider.User entry 
= new CriTextBroadcast.LinqToSqlProvider.User();
            
using (CriTextBroadcastDBDataContext context = DataContext)
            {
                entry 
=  context.User.SingleOrDefault(expression);
            }
            
return entry;
        }

        
public void Update(LinqToSqlProvider.User entity)
        {
           
using (CriTextBroadcastDBDataContext context = DataContext)
            {
                context.User.Attach(entry, 
true);
                context.SubmitChanges();
            }
        }
}

 

实际我们用以上代码操作时,会出现此异常:

已尝试 Attach 或 Add 实体,该实体不是新实体,可能是从其他 DataContext 中加载来的......

 

      查了N多资料未果,后来还是在一国外的帖子里看到了类似问题。原来是这个实体对应的表有若干个关联表,如:User -> Message ,User -> Images等,

在生成实体类时会自动产生:EntitySet<Message> Message这样的属性,由于我们在获取实体时并未将这些关联的内容一起读出来,而在附加时(Attach)这些属性便会出现ObjectDisposedException异常,也就是因为之前查询这个实体时的DataContext已经释放掉了导致的。

 

解决方法:

 

代码
/// <summary>
        
/// 辅助LinqToSql实体与原DataContext分离
        
/// </summary>
        
/// <typeparam name="TEntity"></typeparam>
        
/// <param name="entity"></param>
        public static void Detatch<TEntity>(TEntity entity)
        {

            Type t 
= entity.GetType();

            System.Reflection.PropertyInfo[] properties 
= t.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);

            
foreach (var property in properties)
            {

                
string name = property.Name;

                
if (property.PropertyType.IsGenericType &&

                property.PropertyType.GetGenericTypeDefinition() 
== typeof(EntitySet<>))
                {

                    property.SetValue(entity, 
nullnull);

                }

            }

            System.Reflection.FieldInfo[] fields 
= t.GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);

            
foreach (var field in fields)
            {

                
string name = field.Name;

                
if (field.FieldType.IsGenericType &&

                field.FieldType.GetGenericTypeDefinition() 
== typeof(EntityRef<>))
                {

                    field.SetValue(entity, 
null);

                }

            }

            System.Reflection.EventInfo eventPropertyChanged 
= t.GetEvent("PropertyChanged");

            System.Reflection.EventInfo eventPropertyChanging 
= t.GetEvent("PropertyChanging");

            
if (eventPropertyChanged != null)
            {

                eventPropertyChanged.RemoveEventHandler(entity, 
null);

            }

            
if (eventPropertyChanging != null)
            {

                eventPropertyChanging.RemoveEventHandler(entity, 
null);

            }

        }

 

应在获得实体后使用Detach(entity)方法将实体与原DataContext分离,然后再附加(Attach)到新的DataContext中去

posted @ 2010-01-20 14:15 码农.KEN 阅读(1360) | 评论 (5)编辑

注:本文转载自阿黎在CSDN的博客

(一)  概述
string和CString均是字符串模板类,string为标准模板类(STL)定义的字符串类,已经纳入C++标准之中;
CString(typedef CStringT<TCHAR, StrTraitMFC<TCHAR>> CString)为Visual C++中最常用的字符串类,继承自CSimpleStringT类,主要应用在MFC和ATL编程中,主要数据类型有char(应用于ANSI),wchar_t(unicode),TCHAR(ANSI与unicode均可);
char*为C编程中最常用的字符串指针,一般以'\0'为结束标志;
(二)  构造
       string是方便的,可以从几乎所有的字符串构造而来,包括CString和char*;
        CString次之,可以从基本的一些字符串变量构造而来,包括char*等;
        char*没有构造函数,仅可以赋值;
        举例:
char* psz = “joise”;
CString cstr( psz );
string str( cstr );
(三)  运算符重载
a)       operator=
        string是最方便的,几乎可以直接用所有的字符串赋值,包括CString和char*;
        CString次之,可以直接用些基本的字符串赋值,包括char*等;
        char*只能由指针赋值,并且是极危险的操作,建议使用strcpy或者memcpy,而且char*在声明的时候如未赋初值建议先设为NULL,以避免野指针;
        举例:
char *psz = NULL;
psz = new char[10]; //当然,以上的直接写成char *psz = new char[10];也是一样
memset( psz, 0, 10 );
strcpy( psz, “joise” );
CString cstr;
cstr = psz;
string str;
str = psz;
str = cstr;
delete []psz;
b)          operator+
        string与CString差不多,可以直接与char*进行加法,但不可以相互使用+运算符,即string str = str + cstr是非法的,须转换成char*;
        char*没有+运算,只能使用strcat把两个指针连在一起;
        举例:
char* psz = “joise”;
CString cstr = psz;
cstr = cstr + psz;
string str = psz;
str = str + str + psz;
strcat( psz, psz );
strcat( psz, cstr );//合法
strcat( psz, str );//非法,由此可见,CString可自动转换为const char*,而string不行
c)      operator +=
        string是最强大的,几乎可以与所有的字符串变量+=,包括CString和char*;
        CString次之,可以与基本的一些字符串变量进行+=而来,包括char*等;
        char*没有+=运算符,只能使用strcat把两个指针连在一起;
d)      operator[]
    CString最好,当越界时会抛出断言异常;
    string与char*下标越界结果未定义;
        举例:
char* psz = “joise”;
CString cstr = psz;
cout << cstr[8];
string str = psz;
cout << str[8];
cout << psz[8];
e)       operator== 、operator!=、operator> 、operator< 、operator>= 、perator<=
        CString与string之间不可以进行比较,但均可以与char*进行比较,并且比较的是值,而不是地址;
       cout << ( psz == cstr );
       cout << ( psz == str );
       cout << ( str == psz );
       cout << ( cstr == psz );//以上代码返回均为1
(四)  常用算法
a)       查找
作用 char* string CString
查找指定值 strchr
strstr
strrstr
strspn find Find
第一个匹配的值   fild_first_of FindOneOf
从后面开始查找     ReserveFind
指定匹配方式   find_if  


注:find_if中是把范围内的值挨个代入匹配函数直至返回true
b)      比较
作用 char* string CString
查找指定值(区分大小写) strcmp
strncmp
strcoll
_strncoll operator<
operator>
operator<=
operator>=
operator==
operator!= Collate
Compare
查找指定值(不区分大小写) _stricmp
_strnicmp
_stricoll
_strnicoll   CollateNoCase
CompareNoCase


注:返回值如果<0则前面的值小于后面的值,反之亦然
c)      替换
作用 char* string CString
查找指定值 _strset
_strnset replace
replace_copy
replace_copy_if
replace_if
  Replace


d)      插入
作用 char* string CString
查找指定值   insert Insert


 
 
 
 
e)       增加
作用 char* string CString
动态增加值 strcat push
append Append
AppendChar
AppendFormat


f)      截取
作用 char* string CString
得到部分值 用下标操作 substr Left
Mid
Right
Truncate


g)      移除
作用 char* string CString
移除部份值   remove Remove
移除空白值 RemoveBlanks
注:此为ATL提供,非C函数 remove_if Trim
TrimLeft
TrimRigth


h)      转换大小写
作用 char* string CString
转换大小写 _strlwr
_strupr   MakeLower
MakeUpper


i)       与其他类型转换
作用 char* string CString
转化为数字 atoi
atod
atof   Format
转化为char*   c_str GetBuffer
GetBufferSetLength


j)       格式化
作用 char* string CString
格式化 sprintf   Format


k)      得到长度
作用 char* string CString
得到长度 strlen length GetLength
得到大小   size GetAllocLength


l)      判断为空
作用 char* string CString
判断是否为空 判断是否==NULL或者第一个字符是否是’\0’ empty IsEmpty


m)        重定义大小
作用 char* string CString
重定义大小 realloc
new resize GetBufferSetLength


n)        释放资源
作用 char* string CString
释放 free
delete (delete[])   ReleaseBuffer
ReleaseBufferSetLength


(五)  安全性
CString > string > char*
(六)  灵活性
CString > string >char*
(七)  可移植性
char* = string > CString
  总结
综上所述,在MFC、ATL中使用字符串尽量使用CString,毕竟都是微软的孩子,各方面都比其它更有优势,而在非微软平台上或对移植性要求较高的场合推荐使用string,标准模板库提供了那么强大的泛型算法,没必要再自己去造车轮。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/cmoring/archive/2006/04/12/660482.aspx

posted @ 2009-09-27 14:39 码农.KEN 阅读(51) | 评论 (0)编辑

一、WM5以前的系统中一般都是使用的CEDB数据库,EDB是WM5中的新特性之一。为了改善应用程序的性能和长期可移植性,CEDB 已经被 EDB 所取代。EDB 利用了 SQL Mobile 使用的存储子系统,并且提供了明显优于 CEDB 的性能(尤其是在与持久存储区一起使用时)。因为 CEDB 提供了与 EDB 完全相同的函数集 ,所有函数都具有相同的名称和参数列表。但是EDB中也包含了CEDB中所没有函数,并且创建方法也不相同了,要比CEDB复杂。

二、EDB数据库的创建和基本操作
1.创建数据库卷:CeMountDBVol( );//创建卷
CeCreateDatabaseWithProps();//卷创建成功后创建EDB
CeCreateSession();//EDB创建成功后创建session,用于打开EDB
CeOpenDatabaseInSession();//打开EDB
创建EDB时前还要创建一个CEDBASEINFOEX对象,这个对象用于创建EDB中的info,用于设定EDB。
在打开时还要维护一个全局的HANDLE,在以后的操作中是要使用的.
2.对数据库进行读,写,删除的操作
CeSeekDatabaseEx();//定位所要找的数据
CeReadRecordPropsEx();//读出定位的数据
创建一个CEPROPVAL对象,将所要定位数据的条件传给这个结构。
CeWriteRecordProps();//数据写入EDB
创建一个CEPROPVAL对象,或对象数组,将所要写入的数据传给这些对象。
CeSeekDatabaseEx();//定位要删除的数据
CeDeleteRecord();//删除定位的数据
CeWriteRecordProps();//数据写入新数据到EDB覆盖原数据
CloseHandle(打开时的句柄);
3.其他的一些数据库操作函数

列举数据库: CeFindFirstDatabaseEx和CeFindNextDatabase

获得数据库的信息:CeOidGetInfoEx

//在EDB的消息函数中用到

释放通告消息结构体:CeFreeNotification
将数据缓冲到flash上:CeFreeNotification
获得打开的数据库所使用的句柄:CeGetDBInformationByHandle

设置数据库的各种参数:CeSetDatabaseInfoEx

列举所有转载的数据库卷并返回卷名:CeEnumDBVolumes
三、以下是EDB代码示例
 CEOID oid = NULL;
 CEGUID guidVol = {0,};
 BOOL fOK = true;
 HANDLE h = INVALID_HANDLE_VALUE;
 LPWSTR lpwszDBVol = L"volume.db";

 SORTORDERSPECEX s =
 {
  2, // wVersion should be 2 for EDB
  1, // wNumProps
  0, // wKeyFlags
  0, // wReserved
  0, //rgPropID,
  { 0 } //rgdwFlags
 };

 CEDBASEINFOEX info =
 {
  2, // wVersion must be 2 for EDB
  0, // wNumSortOrder
  (CEDB_VALIDNAME | CEDB_VALIDTYPE | CEDB_VALIDSORTSPEC), // dwFlags
  L"Table1", // szDbaseName
  0x777, // dwDbaseType
  4,/*NULL, // dwNumRecords*/
  NULL, // dwSize (Not used by EDB)
  {0,}, //ftLastModified (Not used by EDB)
 };

 CEPROPVAL val =
 {
  0,    // propid
  NULL, // wLenData - can be garbage on entry
  NULL, // wFlags
  0 
 };

 s.rgPropID[0] = CEVT_LPWSTR;
 val.propid = CEVT_LPWSTR;


 CEPROPSPEC CEPropSpec[4];
 CEPropSpec[0].wVersion = 1;
 CEPropSpec[0].propid = CEVT_LPWSTR;
 CEPropSpec[0].dwFlags = 0;
 CEPropSpec[0].pwszPropName = TEXT("Name");
 CEPropSpec[0].cchPropName = CEDB_MAXDBASENAMELEN;


 // The Following .
 CEPropSpec[1].wVersion = 1;
 CEPropSpec[1].propid = CEVT_LPWSTR;
 CEPropSpec[1].dwFlags = 0;
 CEPropSpec[1].pwszPropName = TEXT("Phone");
 CEPropSpec[1].cchPropName = CEDB_MAXDBASENAMELEN;

 // The Following .
 CEPropSpec[2].wVersion = 1;
 CEPropSpec[2].propid = CEVT_LPWSTR;
 CEPropSpec[2].dwFlags = 0;//0;
 CEPropSpec[2].pwszPropName = TEXT("Content");
 CEPropSpec[2].cchPropName = CEDB_MAXDBASENAMELEN;

 // The Following .
 CEPropSpec[3].wVersion = 1;
 CEPropSpec[3].propid = CEVT_LPWSTR;
 CEPropSpec[3].dwFlags = 0;//0;
 CEPropSpec[3].pwszPropName = TEXT("Isread");
 CEPropSpec[3].cchPropName = CEDB_MAXDBASENAMELEN;

 if (!CeMountDBVolEx(&guidVol, lpwszDBVol, NULL, CREATE_ALWAYS))
 {
  fOK = false;
  goto exit;
 }

 if ((oid = CeCreateDatabaseWithProps(&guidVol, &info, 0, CEPropSpec)) == NULL)
 {
  fOK = false;
  goto exit;
 }


 if ((h = CeOpenDatabaseInSession(NULL, &guidVol, &oid, NULL, NULL,
  0, NULL)) == INVALID_HANDLE_VALUE)
 {
  fOK = false;
  goto exit;
 }

 CEPROPVAL pProp[4];
 pProp[0].propid = PID_NAME;
 pProp[0].wFlags = 0;
 pProp[0].wLenData = 0;
 pProp[0].val.lpwstr = L"777rewr";

 pProp[1].propid = PID_PHONE;
 pProp[1].wFlags = 0;
 pProp[1].wLenData = 0;
 pProp[1].val.lpwstr = L"888rer";

 pProp[2].propid = PID_CONTENT;
 pProp[2].wFlags = 0;
 pProp[2].wLenData = 0;
 pProp[2].val.lpwstr = L"123rewr";

 pProp[3].propid = PID_ISREADED;
 pProp[3].wFlags = 0;
 pProp[3].wLenData = 0;
 pProp[3].val.lpwstr = L"234rewr";

 //Write records.
 for(int i = 0; i < 100; ++i)
  oid = CeWriteRecordProps(h, 0, 4, pProp);

 //Add records.
 CeWriteRecordProps(h, 0, 4, pProp);

 

 CeFlushDBVol(&guidVol); // Just being paranoid!
 CloseHandle(h);


exit:

 CeUnmountDBVol(&guidVol);

查找及删除操作示例:
bool fOK = true;
 CEOID oid = NULL;
 CEOID oidRow = NULL;
 CEGUID guidVol;
 HANDLE h = INVALID_HANDLE_VALUE;
 HANDLE    hDBOpened = NULL;

 CREATE_INVALIDGUID(&guidVol);

 if (!CeMountDBVolEx(&guidVol, L"volume.db", NULL, OPEN_EXISTING))
 {
  fOK = false;
  MessageBox(L"Err!!!");
 }

 
 // Open Database by Name to get its oid.
 if ((h = CeOpenDatabaseInSession(NULL, &guidVol, &oid, L"Table1", NULL,
  CEDB_AUTOINCREMENT, NULL)) == INVALID_HANDLE_VALUE)
 {
  fOK = false;
  MessageBox(L"Err!!!");
 }

 CEOIDINFOEX ceoidInfoEx;
 memset(&ceoidInfoEx,0,sizeof(CEOIDINFOEX));
 ceoidInfoEx.wVersion = 2;

//  if (!CeOidGetInfoEx2(&guidVol, oid, &ceoidInfoEx))
//  {
//   DWORD err = GetLastError();
//   MessageBox(_T("CeOidGetInfoEx2  error!!!"));
//  } 
//  
//  int Leng = ceoidInfoEx.infDatabase.dwNumRecords;
//  CString cs;
//  cs.Format(L"%d",Leng);
//  MessageBox(cs);

 CeSeekDatabaseEx(h, CEDB_SEEK_BEGINNING, 0, 0, NULL);

 WORD          dwPropId = 0;
 DWORD         dwSizeOfBuffer = 0;
 CEOID         ceoidFindRecord = 0;
 WORD          wNumRecProps = 0;
 LPBYTE        lpRecProps = NULL;
 PCEPROPVAL    pCePropVal = NULL;
 DWORD         dwBufLen = 256;
 BOOL m_bFlag = FALSE;
 
 int m_iCount = 0;
 while(ceoidFindRecord = CeReadRecordPropsEx(h, CEDB_ALLOWREALLOC, &dwPropId, NULL, &lpRecProps, &dwSizeOfBuffer, NULL))
 {
  if(GetLastError() != ERROR_NO_MORE_ITEMS)
  {
   pCePropVal = (PCEPROPVAL)lpRecProps;
   LPWSTR lpnum;
   if (m_iCount%2)
    lpnum = pCePropVal[3].val.lpwstr;
   else
    lpnum = pCePropVal[1].val.lpwstr;


  TRACE(L"%d=%s\n",m_iCount,lpnum);
 
   ++m_iCount;
   if(!lpnum )
   {
    CeDeleteRecord(h, ceoidFindRecord);
    m_bFlag = FALSE;
   }
   else
    m_bFlag = TRUE;
  } 
 }
 CString str;
 str.Format(L"%d",m_iCount);
 MessageBox(str);

 if (h)
  CloseHandle(h);

 if(&guidVol)
 {
  CeFlushDBVol(&guidVol);
  CeUnmountDBVol(&guidVol);
 }

头文件:extern "C"
{
#include <windbase_edb.h>
}

#define EDB

posted @ 2009-08-20 16:34 码农.KEN 阅读(239) | 评论 (0)编辑
在C#中使用DllImport调用C++的动态库时,发现直接使用DLL中的函数名作为入口点·会出错,找不到该入口点。通过工具查看DLL后才发现所有函数名都变成“乱码”了;
不过这些都不是乱码,而是有规则的。现转载一篇规则说明,在此感谢原作者。

C++编译时函数名修饰约定规则:   
  __stdcall调用约定:   
  1、以"?"标识函数名的开始,后跟函数名;  
 
  2、函数名后面以"@@YG"标识参数表的开始,后跟参数表; 
  
  3、参数表以代号表示:   
  X--void   ,   
  D--char,   
  E--unsigned   char,   
  F--short,   
  H--int,   
  I--unsigned   int,   
  J--long,   
  K--unsigned   long,   
  M--float,   
  N--double,   
  _N--bool,   
  ....   
  PA--表示指针,后面的代号表明指针类型,如果相同类型的指针连续出现,以"0"代替,一个"0"代表一次重复;   
  4、参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所指数据类型前;   
  
  5、参数表后以"@Z"标识整个名字的结束,如果该函数无参数,则以"Z"标识结束。   
  其格式为"?functionname@@YG*****@Z"或"?functionname@@YG*XZ",例如   
                      int   Test1(char   *var1,unsigned   long)-----“?Test1@@YGHPADK@Z”   
                      void   Test2()                                               -----“?Test2@@YGXXZ”   
    
  __cdecl调用约定:   
  规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的"@@YG"变为"@@YA"。   
  __fastcall调用约定:   
  规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的"@@YG"变为"@@YI"。   
posted @ 2009-08-12 09:30 码农.KEN 阅读(128) | 评论 (0)编辑
     正如本文标题所说,在国内要发展一个真正开放性的社区或博客,基本很难实现。至于那些因涉黄而被河蟹的网站不在此文讨论的范围内。
     
     从WEB2.0概念被提出以来,我就一直陶醉在其中,一直都幻想有一天自己能成为一个知名WEB2.0概念网站的创始人。

     咱就从【视频分享】类网站说起吧,当时国外某视频网站成名后,国内瞬时掀起了一场浩大的跟风模仿秀,记得看过一篇网文称视频分享网站几乎达到了每天增长200家的增长速度,我也是其中一个跟风者^_^,当然我失败了,原因是成本太高,且广电局很快就出了个什么许可证;视频网站受损最严重的应该是56网,记得当时持续关闭了一个多月。后来重开后,发现少了很多喜欢看的节目。。
     最近由于国外的Twitter一夜成名,国内相继出现了饭否,叽歪,嘀咕等,还有些不是很出名的就不提了···。不过不知道大家有没有发现。饭否从7月8日就已经关闭,且该网站的负责人王兴也没有说出一个明确的原因和恢复时间;7月21日,也就是前几天·嘀咕也突然关闭了,页面上显示的是在维护升级中,但大家谁都知道,一个大型网站不太可能连续关闭几天。所以我猜测他们跟饭否的关闭原因应该是雷同的,我正抱怨呢,嘀咕关得也真不是时候^_^,因为我正在参考他们的功能模块··结果。。。其实大部分人对饭否,嘀咕等网站的关闭·都用了同一个词“被河蟹了”。
     
     本来我正在业余的做一个类似的微博客平台,定位也将是绝对开放的,不过现在感觉有点悬。微博客存在的意义就在于简单,真实,无拘无束;你在想什么,做什么,发现了什么,看到了什么等等···,限制了这些,就没有多大价值了。
    
     最后希望大家在评论时··请尽量避开政治话题,如X权,XX自由等等字眼别出现了。
posted @ 2009-07-23 12:07 码农.KEN 阅读(1035) | 评论 (30)编辑
     摘要: 近日正在写个商城系统,打算自己开个服装店的,o(∩_∩)o...哈哈大家都知道商城系统中是离不开购物车的,据观察,网上大多数商城程序的购物车都是采用的一种比较简单的存储方式来实现购物车,那就是把选中了的ID直接拼接起来。这种做法当然在需求不高的情况下足矣,可是想要拥有一个更健壮的购物车的话,却不能满足了。 我的方法是将购物车内商品的几个基本必要属性都要存储起来,如:品名、...  阅读全文
posted @ 2007-11-28 16:41 码农.KEN 阅读(3088) | 评论 (32)编辑
     摘要: 就是这个类,继承它吧!让你的窗体有打开和关闭的时候淡入淡出。很酷的Style,是不是有点像Windows Vista。(注意:继承类窗体初始化属性Opacity=0) public class OpacityShowStyleForm:System.Windows.Forms.Form { System.Single step = 0.05f; public System.Single Step ...  阅读全文
posted @ 2007-10-31 17:23 码农.KEN 阅读(169) | 评论 (1)编辑