www.allpaul.com

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

Programming

July 2008 - Posts

  • 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.

     

  • Adding computed properties to Entity Framework Entities

    I have been working on a project using the Entity Framework.  One of the many cool features of the framework is it generates entity classes as partial classes so you, or in this case I, can extend an entity to include computed properties or methods.

    In this example I have a Contact entity.  It has many properties including, FirstName, MiddleInitial and LastName.  I'd like to be able to access a property called FullName so I don't have to jump through all kinds of string null value checks and concatenation every time I need to display the contact's name. So, here is my entity Contact from the Entity Designer

    Contact Entity

    I can add to the partial class to include the property by creating a new class file (Contact.cs) and adding the correct namespace and including the partial keyword...Like this 

    namespace DBModel 
    { 
    
        public partial class Contact 
        { 
            public string FullName 
            { 
                get 
                { 
                    string ret = string.Empty; 
                    if (!String.IsNullOrEmpty(FirstName)) 
                        ret += FirstName; 
                    if (!String.IsNullOrEmpty(MiddleInitial)) 
                        ret += " " + MiddleInitial; 
                    if (!String.IsNullOrEmpty(LastName)) 
                        ret += " " + LastName; 
                    return ret; 
                } 
            } 
        } 
    
    }

    Now every time I need the contact's name I can just do a

         myContact.FullName

    Sweet!

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