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.