www.allpaul.com

I needed somewhere to put all this stuff
Welcome to www.allpaul.com Sign in | Join | Help
in Search

Programming

Deriving entities from a common interface

My current project has this concept of Activities.  Activities are defined as anything we want to track for a particular Company or Contact in the database.  A typical Activity may be

ID = 21

Description = Contacted office

IsCompanyOnly = false

Now, as I said a company or contact may have these activities added so there are two tables in the database to facilitate this...tbl_Company_Activities and tbl_Contact_Activities...But for this discussion we don't care about the tables as much as the Entities generated from them.

Here is a diagram of how this is all shakes out (there is more than just this activity scenario going on in this diagram, so just focus on the Activity, CompanyActivity and ContactActivity entities):

 

You see how they are exactly the same except their type CompanyActivity vs ContactActivity and the reference to either a Company or Contact?  All of the other fields are the same...And it just so happens that I need to get a list of all company and contact activities for a given company...I smelled an interface. I am going to extract the common fields Notes, ActivityDate, User, and ActivityCode and then add readonly (get properties) for the Type and RecordID (company or contact ID). here is that interface 

   1:  using System;
   2:  using MyModel;
   3:   
   4:  public interface IActivityRecord
   5:  {
   6:      string Notes
   7:      {
   8:          get;
   9:          set;
  10:      }
  11:   
  12:      DateTime ActivityDate
  13:      {
  14:          get;
  15:          set;
  16:      }
  17:   
  18:      DbUser User
  19:      {
  20:          get;
  21:          set;
  22:      }
  23:   
  24:      RecordInfoType RecordType
  25:      {
  26:          get;
  27:      }
  28:   
  29:      int RecordId
  30:      {
  31:          get;
  32:      }
  33:   
  34:      Activity ActivityCode
  35:      {
  36:          get;
  37:          set;
  38:      }
  39:  }


Okay so now I need to implement this interface.  Remember that my model already defined CompanyActivity and Contact as containing  Notes, ActivityDate, User, and ActivityCode, so the only implementations that are up to me are the RecordType and RecordId.  It should be said at this point that RecordType is of type RecordInfoType which is an Enum that contains Company and Contact.  It should aslo be said that this next example code snippet builds upon my previous example Adding computed properties to Entity Framework Entities which shows you how to extend model-generated entities through partial classes.

   1:  using System.Linq;
   2:   
   3:  namespace MyModel
   4:  {
   5:      public partial class ContactActivity : IActivityRecord
   6:      {
   7:   
   8:          public RecordInfoType RecordType
   9:          {
  10:              get { 
  11:                  return RecordInfoType.Contact; }
  12:              
  13:          }
  14:   
  15:          public int RecordId
  16:          {
  17:              get
  18:              {
  19:                  int ret = 0;
  20:                  if (this.ContactReference.IsLoaded)
  21:                      ret = this.Contact.ID;
  22:                  else
  23:                  {
  24:                      using (MyEntities se = new MyEntities())
  25:                      {
  26:                          ret = (from a in se.ContactActivities where a.ID == 
                                       this.ID select a.Contact.ID).FirstOrDefault();
  27:                      }
  28:                  }
  29:                  return ret;
  30:              }
  31:          }
  32:      }
  33:  }

 That was the ContactActivity now here is the CompanyActivity:

   1:  using System.Linq;
   2:   
   3:  namespace MyModel
   4:  {
   5:      public partial class CompanyActivity : IActivityRecord
   6:      {
   7:   
   8:          public RecordInfoType RecordType
   9:          {
  10:              get { return RecordInfoType.Company; }
  11:          }
  12:   
  13:          public int RecordId
  14:          {
  15:              get
  16:              {
  17:                  int ret = 0;
  18:                  if (this.CompanyReference.IsLoaded)
  19:                      ret = this.Company.ID;
  20:                  else
  21:                  {
  22:                      using (MyEntities se = new MyEntities())
  23:                      {
  24:                          ret = (from a in se.CompanyActivities 
                                    where a.ID == this.ID select a.Company.ID).FirstOrDefault();
  25:                      }
  26:                  }
  27:                  return ret;
  28:              }
  29:          }
  30:      }
  31:  }

Cool, huh? Now I can bind a

IEnumerable<IActivityRecord>

to a GridView or work with it as a collection by retrieving it using linq...Oh, wait, I'll still need to downcast, here is a method that takes a Company object and returns a IList<IActivityRecord> of all the activities for the company and all its contacts:

 

   1:   public IList<IActivityRecord> getAllActivities(Company _company)
   2:      {
   3:          IList<IActivityRecord> ret = null;
   4:          using (MyEntities se = new MyEntities())
   5:          {
   6:              IEnumerable<CompanyActivity> companyactivities =
   7:                  (from ca in se.CompanyActivities
                     .Include("Company").Include("ActivityCode").Include("User")
   8:                   where ca.Company.ID == _company.ID
   9:                   select ca);
  10:   
  11:              ret = companyactivities.ToList()
  12:                  .ConvertAll(obj => obj as IActivityRecord);
  13:   
  14:              IEnumerable<ContactActivity> contactactivities =
  15:                  (from ca in se.ContactActivities
                        .Include("Contact").Include("ActivityCode").Include("User")
  16:                   where ca.Contact.Company.ID == _company.ID
  17:                   select ca);
  18:   
  19:              ret.Union(contactactivities.ToList()
  20:                  .ConvertAll(obj => obj as IActivityRecord));
  21:          }
  22:          return ret;
  23:      }

 

Now there would need to be some logic on the consumer side to use the collection in other ways than just straightfroward databinding, but the RecordType and RecordID properties should allow the consumer to do what ever operations they need to.

Good luck.

 

Only published comments... Jul 17 2008, 02:10 PM by paully21

About paully21

 

Powered by Community Server (Non-Commercial Edition), by Telligent Systems