graber
asked on
moving an image to and from a database to the application
What follows are the example class that are responsible for fetching information from the database. The one piece of information that I need help is the bitmap. TestDBSet (inherited from CRecordSet) has the image (m_Image) as a CLongBinary. How do I get it to the View class (CTestDBView)? I have no Idea how to proceed. Not that I thought it would be that easy, but from the view class I dropped a bitmap image and attempted the <cntrl> double click on the bmp. The wiz wasn't the wiz he was. Nothing.
500 pts for the guy who will help me work through this.
Garaber
?????????????????????????? The RecordView Class????????????????????? ??
class CTestDBSet;
class CTestDBView : public CRecordView
{
protected: // create from serialization only
CTestDBView();
DECLARE_DYNCREATE(CTestDBV iew)
public:
//{{AFX_DATA(CTestDBView)
enum { IDD = IDD_TESTDB_FORM };
CTestDBSet* m_pSet;
//}}AFX_DATA
// Attributes
public:
CTestDBDoc* GetDocument();
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CTestDBVie w)
public:
virtual CRecordset* OnGetRecordset();
virtual BOOL PreCreateWindow(CREATESTRU CT& cs);
protected:
virtual void DoDataExchange(CDataExchan ge* pDX); // DDX/DDV support
virtual void OnInitialUpdate(); // called first time after construct
virtual BOOL OnPreparePrinting(CPrintIn fo* pInfo);
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CTestDBView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
//{{AFX_MSG(CTestDBView)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
////////////////////////// ////////// ////////// ////////// ////////// ////////// /
// CTestDBView
IMPLEMENT_DYNCREATE(CTestD BView, CRecordView)
BEGIN_MESSAGE_MAP(CTestDBV iew, CRecordView)
//{{AFX_MSG_MAP(CTestDBVie w)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CRecordView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_D IRECT, CRecordView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_P REVIEW, CRecordView::OnFilePrintPr eview)
END_MESSAGE_MAP()
////////////////////////// ////////// ////////// ////////// ////////// ////////// /
// CTestDBView construction/destruction
CTestDBView::CTestDBView()
: CRecordView(CTestDBView::I DD)
{
//{{AFX_DATA_INIT(CTestDBV iew)
m_pSet = NULL;
//}}AFX_DATA_INIT
// TODO: add construction code here
}
CTestDBView::~CTestDBView( )
{
}
void CTestDBView::DoDataExchang e(CDataExc hange* pDX)
{
CRecordView::DoDataExchang e(pDX);
//{{AFX_DATA_MAP(CTestDBVi ew)
DDX_FieldText(pDX, IDC_LASTNAME, m_pSet->m_LastName, m_pSet);
DDX_FieldText(pDX, IDC_FIRSTNAME, m_pSet->m_FirstName, m_pSet);
DDX_FieldText(pDX, IDC_PHONE, m_pSet->m_Telephone, m_pSet);
//}}AFX_DATA_MAP
}
BOOL CTestDBView::PreCreateWind ow(CREATES TRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CRecordView::PreCreateWind ow(cs);
}
void CTestDBView::OnInitialUpda te()
{
m_pSet = &GetDocument()->m_testDBSe t;
CRecordView::OnInitialUpda te();
ResizeParentToFit();
}
////////////////////////// ////////// ////////// ////////// ////////// ////////// /
// CTestDBView printing
BOOL CTestDBView::OnPreparePrin ting(CPrin tInfo* pInfo)
{
// default preparation
return DoPreparePrinting(pInfo);
}
void CTestDBView::OnBeginPrinti ng(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add extra initialization before printing
}
void CTestDBView::OnEndPrinting (CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add cleanup after printing
}
////////////////////////// ////////// ////////// ////////// ////////// ////////// /
// CTestDBView diagnostics
#ifdef _DEBUG
void CTestDBView::AssertValid() const
{
CRecordView::AssertValid() ;
}
void CTestDBView::Dump(CDumpCon text& dc) const
{
CRecordView::Dump(dc);
}
CTestDBDoc* CTestDBView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKind Of(RUNTIME _CLASS(CTe stDBDoc))) ;
return (CTestDBDoc*)m_pDocument;
}
#endif //_DEBUG
////////////////////////// ////////// ////////// ////////// ////////// ////////// /
// CTestDBView database support
CRecordset* CTestDBView::OnGetRecordse t()
{
return m_pSet;
}
////////////////////////// ////////// ////////// ////////// ////////// ////////// /
// CTestDBView message handlers
?????????????????????????? The RecordSet Class????????????????????? ??
class CTestDBSet : public CRecordset
{
public:
CTestDBSet(CDatabase* pDatabase = NULL);
DECLARE_DYNAMIC(CTestDBSet )
// Field/Param Data
//{{AFX_FIELD(CTestDBSet, CRecordset)
long m_ID;
CString m_FirstName;
CString m_LastName;
CString m_Telephone;
CLongBinary m_Image;
//}}AFX_FIELD
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CTestDBSet )
public:
virtual CString GetDefaultConnect(); // Default connection string
virtual CString GetDefaultSQL(); // default SQL for Recordset
virtual void DoFieldExchange(CFieldExch ange* pFX); // RFX support
//}}AFX_VIRTUAL
// Implementation
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
};
// TestDBSet.cpp : implementation of the CTestDBSet class
//
#include "stdafx.h"
#include "TestDB.h"
#include "TestDBSet.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
////////////////////////// ////////// ////////// ////////// ////////// ////////// /
// CTestDBSet implementation
IMPLEMENT_DYNAMIC(CTestDBS et, CRecordset)
CTestDBSet::CTestDBSet(CDa tabase* pdb)
: CRecordset(pdb)
{
//{{AFX_FIELD_INIT(CTestDB Set)
m_ID = 0;
m_FirstName = _T("");
m_LastName = _T("");
m_Telephone = _T("");
m_nFields = 5;
//}}AFX_FIELD_INIT
m_nDefaultType = snapshot;
}
CString CTestDBSet::GetDefaultConn ect()
{
return _T("ODBC;DSN=TestDB");
}
CString CTestDBSet::GetDefaultSQL( )
{
return _T("[Person]");
}
void CTestDBSet::DoFieldExchang e(CFieldEx change* pFX)
{
//{{AFX_FIELD_MAP(CTestDBS et)
pFX->SetFieldType(CFieldEx change::ou tputColumn );
RFX_Long(pFX, _T("[ID]"), m_ID);
RFX_Text(pFX, _T("[FirstName]"), m_FirstName);
RFX_Text(pFX, _T("[LastName]"), m_LastName);
RFX_Text(pFX, _T("[Telephone]"), m_Telephone);
RFX_LongBinary(pFX, _T("[Image]"), m_Image);
//}}AFX_FIELD_MAP
}
////////////////////////// ////////// ////////// ////////// ////////// ////////// /
// CTestDBSet diagnostics
#ifdef _DEBUG
void CTestDBSet::AssertValid() const
{
CRecordset::AssertValid();
}
void CTestDBSet::Dump(CDumpCont ext& dc) const
{
CRecordset::Dump(dc);
}
#endif //_DEBUG
500 pts for the guy who will help me work through this.
Garaber
??????????????????????????
class CTestDBSet;
class CTestDBView : public CRecordView
{
protected: // create from serialization only
CTestDBView();
DECLARE_DYNCREATE(CTestDBV
public:
//{{AFX_DATA(CTestDBView)
enum { IDD = IDD_TESTDB_FORM };
CTestDBSet* m_pSet;
//}}AFX_DATA
// Attributes
public:
CTestDBDoc* GetDocument();
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CTestDBVie
public:
virtual CRecordset* OnGetRecordset();
virtual BOOL PreCreateWindow(CREATESTRU
protected:
virtual void DoDataExchange(CDataExchan
virtual void OnInitialUpdate(); // called first time after construct
virtual BOOL OnPreparePrinting(CPrintIn
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CTestDBView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
//{{AFX_MSG(CTestDBView)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//////////////////////////
// CTestDBView
IMPLEMENT_DYNCREATE(CTestD
BEGIN_MESSAGE_MAP(CTestDBV
//{{AFX_MSG_MAP(CTestDBVie
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CRecordView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_D
ON_COMMAND(ID_FILE_PRINT_P
END_MESSAGE_MAP()
//////////////////////////
// CTestDBView construction/destruction
CTestDBView::CTestDBView()
: CRecordView(CTestDBView::I
{
//{{AFX_DATA_INIT(CTestDBV
m_pSet = NULL;
//}}AFX_DATA_INIT
// TODO: add construction code here
}
CTestDBView::~CTestDBView(
{
}
void CTestDBView::DoDataExchang
{
CRecordView::DoDataExchang
//{{AFX_DATA_MAP(CTestDBVi
DDX_FieldText(pDX, IDC_LASTNAME, m_pSet->m_LastName, m_pSet);
DDX_FieldText(pDX, IDC_FIRSTNAME, m_pSet->m_FirstName, m_pSet);
DDX_FieldText(pDX, IDC_PHONE, m_pSet->m_Telephone, m_pSet);
//}}AFX_DATA_MAP
}
BOOL CTestDBView::PreCreateWind
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CRecordView::PreCreateWind
}
void CTestDBView::OnInitialUpda
{
m_pSet = &GetDocument()->m_testDBSe
CRecordView::OnInitialUpda
ResizeParentToFit();
}
//////////////////////////
// CTestDBView printing
BOOL CTestDBView::OnPreparePrin
{
// default preparation
return DoPreparePrinting(pInfo);
}
void CTestDBView::OnBeginPrinti
{
// TODO: add extra initialization before printing
}
void CTestDBView::OnEndPrinting
{
// TODO: add cleanup after printing
}
//////////////////////////
// CTestDBView diagnostics
#ifdef _DEBUG
void CTestDBView::AssertValid()
{
CRecordView::AssertValid()
}
void CTestDBView::Dump(CDumpCon
{
CRecordView::Dump(dc);
}
CTestDBDoc* CTestDBView::GetDocument()
{
ASSERT(m_pDocument->IsKind
return (CTestDBDoc*)m_pDocument;
}
#endif //_DEBUG
//////////////////////////
// CTestDBView database support
CRecordset* CTestDBView::OnGetRecordse
{
return m_pSet;
}
//////////////////////////
// CTestDBView message handlers
??????????????????????????
class CTestDBSet : public CRecordset
{
public:
CTestDBSet(CDatabase* pDatabase = NULL);
DECLARE_DYNAMIC(CTestDBSet
// Field/Param Data
//{{AFX_FIELD(CTestDBSet, CRecordset)
long m_ID;
CString m_FirstName;
CString m_LastName;
CString m_Telephone;
CLongBinary m_Image;
//}}AFX_FIELD
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CTestDBSet
public:
virtual CString GetDefaultConnect(); // Default connection string
virtual CString GetDefaultSQL(); // default SQL for Recordset
virtual void DoFieldExchange(CFieldExch
//}}AFX_VIRTUAL
// Implementation
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
};
// TestDBSet.cpp : implementation of the CTestDBSet class
//
#include "stdafx.h"
#include "TestDB.h"
#include "TestDBSet.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//////////////////////////
// CTestDBSet implementation
IMPLEMENT_DYNAMIC(CTestDBS
CTestDBSet::CTestDBSet(CDa
: CRecordset(pdb)
{
//{{AFX_FIELD_INIT(CTestDB
m_ID = 0;
m_FirstName = _T("");
m_LastName = _T("");
m_Telephone = _T("");
m_nFields = 5;
//}}AFX_FIELD_INIT
m_nDefaultType = snapshot;
}
CString CTestDBSet::GetDefaultConn
{
return _T("ODBC;DSN=TestDB");
}
CString CTestDBSet::GetDefaultSQL(
{
return _T("[Person]");
}
void CTestDBSet::DoFieldExchang
{
//{{AFX_FIELD_MAP(CTestDBS
pFX->SetFieldType(CFieldEx
RFX_Long(pFX, _T("[ID]"), m_ID);
RFX_Text(pFX, _T("[FirstName]"), m_FirstName);
RFX_Text(pFX, _T("[LastName]"), m_LastName);
RFX_Text(pFX, _T("[Telephone]"), m_Telephone);
RFX_LongBinary(pFX, _T("[Image]"), m_Image);
//}}AFX_FIELD_MAP
}
//////////////////////////
// CTestDBSet diagnostics
#ifdef _DEBUG
void CTestDBSet::AssertValid() const
{
CRecordset::AssertValid();
}
void CTestDBSet::Dump(CDumpCont
{
CRecordset::Dump(dc);
}
#endif //_DEBUG
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks for responding. Currently the Access database type is an Ole Object. The first two are unfamiliar, or so I believe, from the database side. What are the pro's and cons of each
Simply putting the BMP file in as a long binary is simpler from a programming point of view. The way that an OLE object is stored in an access database is not officially documented, so getting the data in there usually relies on writing some access cba app to automate the manual inserting of an object. Ole objects also take up much more room, not only because of the extra heading info, but also because of the way OLE objects (usually) require both the original data AND the rendered version. You'll find that your database size is MUCH bigger than what you'd expect (going by the size of the bitmap files). The main advantage (if any) of storing them as OLE object is that you can double click on an OLE object in a view of a table and see the picture (via OLE).
The advantage of storing just the BMP data is that it takes less room and is easy to save and retrive and convert to a picture programmatically. You can also use other formats (like JPG) micely. The latest version of Crystal Reports (for example) will recognise raw bmp jpg and gif data in long-binary records (as i understand).
There is lots of info on how to store and reteive raw image data in a datbase (both from MS KB, www.codeguru.com and here at EE)
I have an app that uses a cross between these. It uses the unofficial OLE1 headers etc that Access uses when storing an OLE object .. but avoids putting in the extra (redundant) rendering data, so I don't get the bloat, but still do get the advantages of an OLE object - but I cannot use JPG in this case (which is not a mayjor problem for my particular app as there are few bitmaps and they are small in size).
NOTE: People who know suggest that storing images directly in a datbase is BAD (for a lot of valid reasons). Instead, they recommend you store the images in external files, and instead keep the path to the file name (or URL)in your database. This has great performance and disk-space advantages over storing directly in databases. This is especially the case with very large databases.
The only catch is if you are using Crystal reports. It doesn't support this sort of thing. To make it work, you have to know the layout of your report, use their ActiveX control, and write some VB code .. if you're directly calling the report engine, or using CR stand-alone, then you're stuffed. Please petition you nearest Crystal representative until they support this !!!
The advantage of storing just the BMP data is that it takes less room and is easy to save and retrive and convert to a picture programmatically. You can also use other formats (like JPG) micely. The latest version of Crystal Reports (for example) will recognise raw bmp jpg and gif data in long-binary records (as i understand).
There is lots of info on how to store and reteive raw image data in a datbase (both from MS KB, www.codeguru.com and here at EE)
I have an app that uses a cross between these. It uses the unofficial OLE1 headers etc that Access uses when storing an OLE object .. but avoids putting in the extra (redundant) rendering data, so I don't get the bloat, but still do get the advantages of an OLE object - but I cannot use JPG in this case (which is not a mayjor problem for my particular app as there are few bitmaps and they are small in size).
NOTE: People who know suggest that storing images directly in a datbase is BAD (for a lot of valid reasons). Instead, they recommend you store the images in external files, and instead keep the path to the file name (or URL)in your database. This has great performance and disk-space advantages over storing directly in databases. This is especially the case with very large databases.
The only catch is if you are using Crystal reports. It doesn't support this sort of thing. To make it work, you have to know the layout of your report, use their ActiveX control, and write some VB code .. if you're directly calling the report engine, or using CR stand-alone, then you're stuffed. Please petition you nearest Crystal representative until they support this !!!
ASKER
Man now that was the answer that I was looking for. Not that I'm anyone, but that really helped. Thanks Ronslow. I was out to codeguru and it helped to assimalate some of what you had said originally. I agree with you that putting images into a data base isn't really a good idea, if for no other reason no really understands what's going on. But it does seem to be rather popular. At any rate thanks
garaber
garaber
ASKER