Mixing Table Per Type and Table Per Hierarchy Inheritance

Posted by Matt | Filed under , , , , , ,

When working in Silverlight RIA applications, there are some common scenarios that are useful:

  • Table Per Type inheritance – Useful when you have one table that “extends” another table with additional data.  Your main table would be a common “type” and you’d have one (or more) tables which add more data.  More information
  • Table Per Hierarchy inheritance – Useful when you have one table that has many “types” inside it with some data useful depending on the “type”.  Usually, one column in your table would denote the “type” of data, and from there, your application would read additional columns.  These additional columns often would be unused if a row’s “type” was not of a particular value.  More Information
  • Table Per Concrete Type inheritance – Useful when you want to have a “history” table in addition to the “current” data.  More Information

All 3 of these are useful in their own times.  But what if you needed to mix types?

Here is a particular database scenario which I believe to be quite common:

image


In this setup, we have a database representing an online store.  One table lists all the products.  Some products are shirts, other products are shoes.  Two additional tables exist to provide additional data depending on the product type (similar to Table Per Type).  However, we have a discriminator (ProductType) to determine the product type (similar to Table Per Hierarchy).  In our case, if ProductType == 1, then there’s a Shirt record corresponding to the Product record.

For lack of a better name, I’m calling this Table Per Type Hierarchy inheritance.

By default, entity framework would generate the following:

image

 

This would work, however, there are 3 side-effects to this:

  1. Product has a navigation member called “Shirt”.  This means “Product has a Shirt”.  Likewise, “Shirt has a Product” since Shirt has a navigation member called “Product”.  In reality, “Shirt is a Product”.   This is “unnatural”.
  2. If I wanted to query all the Products which are Shirts, then I’d have to query “where ProductType == 1”.
  3. There are no safeguards to ensure that “if ProductType == 1 then a Shirt record exists”.

Instead, we want to setup a conditional hierarchy.  At first, you may think that we can just use Table Per Hierarchy to create a hierarchy between Shirts and Products and Shoes and Products, then add a conditional for Shirt “where ProductType = 1”.  However, this is not the case.  The entity framework user interface does not allow you to select a member from Product as a condition for Shirt.  Maybe this is a bug.  Maybe you can do this by editing the Xml.  To get this to work, you need to add a proxy entity between Product and Shirt.

Step 1.  Start with your default entity framework setup.

image[8]

 


Step 2.  Remove the 2 associations that were generated.  Click each and delete.

image

 


Step 3.  Remove the ProductType member from Product.

Step 4.  Make Product abstract.

image

Step 5.  This step is exactly as is done for normal Table Per Hierarchy inheritance.  Create a new entity and call it “ShirtProduct”.  Derive this new entity from Product.  Map the new entity to the Products table.  In the mapping, add a condition such that ProductType = 1.  But don’t move any properties from Product to ShirtProduct.

Step 6.  This step is just like normal Table Per Type inheritance.  Derive Shirt from ShirtProduct. 

image

Remove ProductId from Shirt since we already have it in Product.  Once we’ve done that, our entity model should look like this:

image

 

 

Step 7.  Repeat steps 5 and 6 for Shoe, but set it’s condition to “ProductType = 2”.  Our model now looks like:

image

The blue rectangle represents the portion using Table Per Hierarchy inheritance.  The red rectangle represents the portion using Table Per Type inheritance.

If we had any products which did not require extra data in secondary tables, we could just use Table Per Hierarchy inheritance.  For example, if we had a third product type called “Pants”, then we could create a new entity called “Pants” (not “PantsProduct”), derive it from Product and set it’s condition to be ProductType = 3.  In this case, the proxy class is the working class.

To access the classes, we do so just like Table Per Type.  The example code shows ‘get’ functions for a DomainContext in a Silverlight RIA appliication:

public IQueryable<Shirt> GetShirts()
{
	return this.ObjectContext.Products.OfType<Shirt>();
}

public IQueryable<Shoe> GetShoes()
{
	return this.ObjectContext.Products.OfType<Shoe>();
}

When I generated my DomainContext, I chose to retrieve and update the ProductTable.  So my DomainContext already had GetProducts() and InsertProduct().  This means:

  1. I can use GetProducts() to get a list of all products, and
  2. I can insert a product of any type by calling InsertProduct()

Actually, for a Silverlight RIA application, you may choose to not call InsertProduct() directly.  Instead, you can use the following code:

Shirt shirt = new Shirt();
shirt.ProductId = Guid.NewGuid();
shirt.Title = "Red Polo";
shirt.Price = new Decimal(11.99);
shirt.Colour = "Red";
shirt.Style = "Polo";

ProductDomainContext context = 
   (ProductDomainContext)domainDataSource1.DomainContext;
context.Products.Add(shirt);
context.SubmitChanges();

 

Notice 2 things:

  1. I am using the normal entity framework model to insert a Shirt into the list of Products.
  2. I am not setting Product.ProductType anywhere.

The entity framework takes care of inserting the correct data into the Shirts table, the correct data into the Products table, and setting ProductType = 1 properly.

Magical!

Included is a sample Silverlight RIA application that demonstrates this.  It includes a list of all products, a list of shirts, and a list of shoes.  It also inserts a new shirt into the database.

TPTHSample.zip (4.58 MB)

I’d like to thank Lingzhi Sun over on the MSDN Forums for help in this matter.

Ugly Yellow Tooltips in your MFC Application Using the Windows 7 Theme

Posted by Matt | Filed under , , , ,

I found another bug in MFC in Visual Studio 2010, but it’s an easy one to fix.

If you create a new MFC Ribbon project and use the Windows 7 colour scheme, then you’ll notice that the tooltips are ugly and yellow.

image

If you want to get the attractive tooltips back, you need to add a little bit of code.  Pat Brenner gave a solution when I reported the problem on the MSDN Forums.  This solution will work if you are allowing theme switching in your application.  If you are not, then you need to add similar code, elsewhere.  If this is the case for you, add the following code to CMainFrame::OnCreate():

CMFCToolTipInfo ttParams;
ttParams.m_bVislManagerTheme = FALSE;
ttParams.m_bDrawSeparator = FALSE;
ttParams.m_clrFillGradient = afxGlobalData.clrBarFace;
ttParams.m_clrFill = RGB(255, 255, 255);
ttParams.m_clrBorder = afxGlobalData.clrBarShadow;
ttParams.m_clrText = afxGlobalData.clrBarText;
theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,
  RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams);

If you do this, you’ll get the attractive tooltips you’re looking for.

image

Correcting a Windows 7 Ribbon project using Visual Studio 2010

Posted by Matt | Filed under , , ,

So you’ve created a new MFC Ribbon application that has the Windows 7 ribbon look to it.  Unfortunately, when you run the application, it looks like this:

Screen_Bad

Notice the big ugly button in the corner, and the quick access toolbar is not drawn correctly (down arrow menu button).

This happens when you do not select the “Enable visual style switching” option.

image

The correction is to find this line of code in MainFrm.cpp:

CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(
	CMFCVisualManagerWindows7));

and add the following line immediately after it:

m_wndRibbonBar.SetWindows7Look(TRUE);

Once you’ve done that, your window will look correct.

Screen_Good

I’ve reported the issue on Microsoft Connect.  A link to the report can be found here.

Tip: Install the MFC Source Code

Posted by Matt | Filed under ,

I cannot express how many times I’ve needed to step through the MFC source code in order to debug a problem I was having.  Often, the problem ends up being my own issue, but by stepping through the MFC source code, I was able to get a better understanding of what exactly the issue is.

So today’s tip:  make sure you install the MFC source code when you’re installing Visual Studio.  It’s an optional component, so best to do a custom install to ensure it’s selected.

Visual Studio 2010 Launches Today

Posted by Matt | Filed under , ,

Microsoft is releasing the newest version of it’s development environment today.  This new version is slated to include many new features, not only for managed code, but also for unmanaged C++ code.

The launch is comprised of a 2-day event.  The first day has keynotes and talks about Visual Studio 2010.  Day 2 is the official launch for Silverlight 4.

Channel 9 has it’s own launch center set up to cover the 2-day event.

Microsoft has announced the availability (to download or purchase) Visual Studio 2010.

Compatible with Windows 7 Application Testing

Posted by Matt | Filed under , ,

Compatible with Windows 7 Back with Vista, Microsoft had 2 logo designations:  Works with Vista and Certified for Vista.  The former was a free self-test, the latter was an expensive 3rd party test.  For Windows 7, Microsoft has consolidated the two designations into a single logo:  Compatible with Windows 7.  This is done as a self-test using the latest toolkit.

However, not all companies have the time and/or resources to do the testing themselves.  Sometimes it’s more economical to farm the manual work off to another party to do the testing.  Let’s face it, would you rather spend your time adding new features and improvements, or would you rather be spending time testing your application for Windows 7 compatibility?

To meet this need, I’ve started LogoPlus.  LogoPlus is a service where businesses can farm out the manual labour of testing their applications against the toolkit.  They should still make sure they meet the logo requirements.  However, the work of setting up the Windows 7 Ultimate x64 operating systems, testing and re-testing, etc. can be done by LogoPlus.

If you’re in charge of getting your product Compatible with Windows 7 tested, I encourage your to check out the service.  I think you’ll find the the prices are competitive and economical.

Multiple Projects and Include Paths

Posted by Matt | Filed under ,

One thing that I am struggling with in working in new development projects is how to deal with multiple vcproj projects and the include paths that go with them.  What is the best schema for dealing with include folders?  Currently, we copy files that we know are needed in other projects to a common include folder. 

For example, if we have projects A.vcproj and B.vcproj, and B.vcproj requires A.h from A.vcproj, then in A.vcproj we will have a custom build step for A.h to copy it to the common include folder.  B.vcproj will then add the common include folder to it’s include path.  This method avoids having to know which project and which directory contains the header file.  It works well for the 60 projects involved in our main solution file.

There is a caveat to this system:  sometimes it’s not possible to keep a strict dependency tree for projects.  For example, occasionally, there may be 2 projects which create a circular dependency based on include requirements.  We work very hard to avoid this for DLLs.  However, for LIBs, we are less strict.  As such, we cannot rely on one project’s header files being copied before it’s needed by another project.  Our solution was to create a pre-process build step that would parse the project files and perform the copy for all projects before the first one was built.

It’s not elegant, but it works.  And sometimes that’s what matters.

What I’m wondering now is how other companies deal with similar issues.  How do you deal with including files from other projects?  Do you use a common include folder?  Do you hard code the paths to the included files in your #include statement?  Or do you have another system that’s working well for you?

Allowing CView Classes to Handle Tab Navigation

Posted by Matt | Filed under , , ,

Working on a recent project, I wanted to give my CView-derived view class Tab navigation (like CFormView has).  By default, if you add CEdit and other controls to your CView-derived view, pressing Tab will do nothing.  Also, adding CStatic with & accelerators are ignored.

Doing some Googling, I found the following solution.  Add the following function to your CView-derived class:

BOOL CMyView::PreTranslateMessage(MSG* pMsg)
{
  if(IsDialogMessage(pMsg))
    return TRUE;
  else
    return CWnd::PreTranslateMessage(pMsg);
}

At first, it was working great.  However, I noticed that my overall application accelerators were not working.

Looking deeper into CFormView, I found the solution. The above code is not enough.  The following is a more complete solution.

BOOL CMyView::PreTranslateMessage(MSG* pMsg)
{
  ASSERT(pMsg != NULL);
  ASSERT_VALID(this);
  ASSERT(m_hWnd != NULL);

  // allow tooltip messages to be filtered
  if (CView::PreTranslateMessage(pMsg))
    return TRUE;

  // don't translate dialog messages when in Shift+F1 help mode
  CFrameWnd* pFrameWnd = GetTopLevelFrame();
  if (pFrameWnd != NULL && pFrameWnd->m_bHelpMode)
    return FALSE;

  // since 'IsDialogMessage' will eat frame window accelerators,
  //   we call all frame windows' PreTranslateMessage first
  pFrameWnd = GetParentFrame();   // start with first parent frame
  while (pFrameWnd != NULL)
  {
    // allow owner & frames to translate before IsDialogMessage does
    if (pFrameWnd->PreTranslateMessage(pMsg))
      return TRUE;

    // try parent frames until there are no parent frames
    pFrameWnd = pFrameWnd->GetParentFrame();
  }

  // don't call IsDialogMessage if form is empty
  if (::GetWindow(m_hWnd, GW_CHILD) == NULL)
    return FALSE;

  // filter both messages to dialog and from children
  return PreTranslateInput(pMsg);
}

I will admit, this code came directly from CFormView in the MFC source for Visual Studio 2008 (give credit where credit is due).

After including this code in my class, tab navigation is working as well as overall application accelerators.

Unresolved CLSID and IID identifiers

Posted by Matt | Filed under , ,

When using COM objects, occasionally, you may run into “LNK2001 unresolved external” errors.  This is often because the header file that declares the GUID for the COM object or interface is using DEFINE_GUID.  This macro is setup to declare the GUID as extern, meaning it needs to finally reside somewhere.  The error you are getting means that it has no home.

So solve this issue, include “InitGuid.h” before your header file that is declaring the GUID.  Ultimately, it actually needs to be before guiddef.h so you may need to include it in your precompiled headers if guiddef.h is being included somewhere in there.

In my case, I was including “Evalcom2.h” and CLSID_EvalCom2 and IID_IValidate were unresolved.  To solve it, I did this:

// So the GUIDs get defined (and not just declared)
#include <InitGuid.h>
#include <Evalcom2.h>

More information can be found on Microsoft’s page, here.

Desktop Computers with Batteries

Posted by Matt | Filed under , ,

Recently, we’ve been having a lot of bad weather in the area. This caused quite a few power failures in our office.  They only lasted 1 or 2 seconds, but it was enough to hear a simultaneous set of curses and moans throughout the office:  everyone’s desktop rebooted.

Luckily, I work on a laptop, so my laptop battery saved me.  This got me thinking.  Why don’t desktop power supply manufacturers create power supplies with a very small battery in them?  I’m not talking about a full UPS, but just a battery with enough juice to prevent the desktop from rebooting when there’s a 1 or 2 second power failure.