New Posts New Posts RSS Feed: Abstract Classes
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

Abstract Classes

 Post Reply Post Reply
Author
orcities View Drop Down
Senior Member
Senior Member
Avatar

Joined: 28-Aug-2007
Location: United States
Posts: 454
Post Options Post Options   Quote orcities Quote  Post ReplyReply Direct Link To This Post Topic: Abstract Classes
    Posted: 28-Apr-2010 at 1:46pm
How do we do abstract classes with 2010?
For example if I want to base some entites of an an AuditEntity or BaseEntity with additional features?
Back to Top
davidklitzke View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 14-Jun-2007
Posts: 715
Post Options Post Options   Quote davidklitzke Quote  Post ReplyReply Direct Link To This Post Posted: 28-Apr-2010 at 2:19pm

Have you looked at this post?

 
 
Back to Top
orcities View Drop Down
Senior Member
Senior Member
Avatar

Joined: 28-Aug-2007
Location: United States
Posts: 454
Post Options Post Options   Quote orcities Quote  Post ReplyReply Direct Link To This Post Posted: 28-Apr-2010 at 2:29pm
How do I get it to show up in the BaseType dropdown. I created a class called BaseEntity : Entity then compiled but it didn't show up.
Basically do I have to create an entity and not provide a key?
Back to Top
orcities View Drop Down
Senior Member
Senior Member
Avatar

Joined: 28-Aug-2007
Location: United States
Posts: 454
Post Options Post Options   Quote orcities Quote  Post ReplyReply Direct Link To This Post Posted: 28-Apr-2010 at 2:30pm
By the way that throws an error.
Back to Top
GregD View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 09-May-2007
Posts: 374
Post Options Post Options   Quote GregD Quote  Post ReplyReply Direct Link To This Post Posted: 29-Apr-2010 at 12:34pm
Originally posted by orcities


How do I get it to show up in the BaseType dropdown. I created a class called BaseEntity : Entity then compiled but it didn't show up. Basically do I have to create an entity and not provide a key?


You don't. The EF doesn't support types not mapped to a backing store, so our BaseEntity exists outside of the EDM. Once you declare it in the DevForce Code Generation section of the EDM properties, all entities in the code generated by DevForce will then inherit from it.

Note that you will need to create (or have DevForce create) the developer partial class for your injected base type in order to do anything useful with it.
Back to Top
orcities View Drop Down
Senior Member
Senior Member
Avatar

Joined: 28-Aug-2007
Location: United States
Posts: 454
Post Options Post Options   Quote orcities Quote  Post ReplyReply Direct Link To This Post Posted: 29-Apr-2010 at 12:37pm
Can you point me to the corect documentation having the code generation automatically have my base class?
Back to Top
GregD View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 09-May-2007
Posts: 374
Post Options Post Options   Quote GregD Quote  Post ReplyReply Direct Link To This Post Posted: 29-Apr-2010 at 5:35pm
Originally posted by orcities


Can you point me to the corect documentation having the code generation automatically have my base class?


While viewing the Entity Data Model in the designer, click in white space to see the properties of the ConceptualEntityModel; then just type the name of the desired class as the value for the Injected base type property.

Here's a pic:


Back to Top
pk55 View Drop Down
Senior Member
Senior Member


Joined: 22-Jul-2009
Location: CA
Posts: 105
Post Options Post Options   Quote pk55 Quote  Post ReplyReply Direct Link To This Post Posted: 29-Apr-2010 at 6:18pm
If you use a name that isn't qualified (with a "." in the name like Namespace.BaseEntity), then DevForce creates this injected base type in the <model>.IB.Designer.cs file for you as a partial class and if you have "Generate Developer Classes" set to true, you'll also have another partial class created as a separate file (MyBaseEntity.cs in the example Greg gave).  If you don't let DevForce generate the developer classes, then you need to create your own partial class.
 
And the forum link that Greg pointed you to does work.  I've got 6 data models (from separate databases) with up to 2 levels of inherited base entities.  I only tell DevForce (via the EDMX) about the base entity that inherits directly from "Entity" and since I used a fully qualified name because I want to share the base type across data models  (like "MyNamespace.MyBaseEntity"), DevForce didn't generate the partial classes for that class in the designer nor as a developer class so I had to create a separate base entity class (one for each level of my inheritence) and also add the DataContract attributes so it would serialize.  Of course to do this with multiple levels of base types, you have to be willing to have some T4 fun.
 
From the MyBaseEntity.cs:
 
    [DataContract]
    [KnownType(typeof(MyBaseEntity))]
    public abstract partial class MyBaseEntity : Entity
{
... stuff
}
From the ChildBaseEntity.cs:
 
[DataContract]
    [KnownType(typeof(ChildBaseEntity))]
    public abstract partial class ChildBaseEntity : MyBaseEntity
{
...more stuff
}
 
Then in the T4 template I switch the data entity to inherit from ChildBaseEntity.
 
If you have any properties added to the base entities, make sure you mark them as [DataMember].  The release notes mentioned this and it is true for base entity fields (page 14):
  1. A custom field intializer that you added to your entity (e.g., private int foo = 42;) may not always be set for every new instance. Our client-side "entity materialization" logic can by-pass field initializations. To ensure that "foo" is initialized, either set it lazily or mark "foo" as a WCF DataMember.

 

Back to Top
GregD View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 09-May-2007
Posts: 374
Post Options Post Options   Quote GregD Quote  Post ReplyReply Direct Link To This Post Posted: 30-Apr-2010 at 11:55am
Originally posted by pk55


 if you have "Generate Developer Classes" set to true, you'll also have another partial class created as a separate file (MyBaseEntity.cs in the example Greg gave). 


Although that is indeed what should happen, when I tested that yesterday, DevForce didn't create the developer partial class for the base type. I entered that into our bug base to be fixed.

Thanks for contributing the additional detail!
Back to Top
orcities View Drop Down
Senior Member
Senior Member
Avatar

Joined: 28-Aug-2007
Location: United States
Posts: 454
Post Options Post Options   Quote orcities Quote  Post ReplyReply Direct Link To This Post Posted: 03-May-2010 at 7:50am
Ok I have them all inheriting from one injected type. Is there a way to do choose the injected type on an entity basis. For example. Table1 : BaseEntity, Table2 : AuditEntity?
 
 
Back to Top
pk55 View Drop Down
Senior Member
Senior Member


Joined: 22-Jul-2009
Location: CA
Posts: 105
Post Options Post Options   Quote pk55 Quote  Post ReplyReply Direct Link To This Post Posted: 03-May-2010 at 9:15am
You have to use a T4 template to do this (http://www.ideablade.com/forum/forum_posts.asp?TID=1721&PID=6755#6755
).
 
Since I wrote that sample on switching parents (where I used the EDMX Summary attribute on the entity to specify the parent to use), I've changed to just make a call to another T4 template that takes the Entity name and looks up the parent to use.
 
Create a new T4 file, in this example, it's called "GetEntityParent.tt" and add it to your solution.  After adding it, remove the Custom Tool name from the file properties in the solution explorer since we don't need this t4 to actually do anything.  It's just an "include" file.  Any entity that you don't want to switch will return an empty string (you could also just default it to whatever your common injected base type is) and the main routine will not change its parent.  Obviously you could use an XML file to hold these relationships as well.  To me, putting them in a code file is just as easy and (in our case) is checked into source control along with the models.
 
<#@ template  language="C#" debug="true" hostSpecific="true" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ Assembly Name="System.Data.Entity.dll" #>
<#@ Assembly Name="Microsoft.VisualStudio.TextTemplating.10.0" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Data.Entity" #>
<#+
 /// <summary>
 /// Code Generation Function to get the parent entity for inheritence in the models
 /// </summary>
 public class GetEntityParentTemplate
 {  
  public string GetEntityParent(string childEntity)
  {
   if (childEntity == "Table1")
   {
    return "BaseEntity";
   }
    
   if (childEntity == "Table2")
   {
    return "AuditEntity";
   }
 
   return string.Empty;
  }
 }
#>
 
Change the other T4 (the one that is <modelname>.edmx.tt) with these bolded changes:
 
<#@ template  language="C#" debug="true" hostSpecific="true" #>
<#@ output extension=".ReadMe" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ Assembly Name="Microsoft.VisualStudio.TextTemplating.10.0" #>
<#@ Assembly Name="IdeaBlade.Core" #>
<#@ Assembly Name="IdeaBlade.VisualStudio.DTE.dll" #>
<#@ Assembly Name="IdeaBlade.VisualStudio.OM.CodeGenerator.dll" #>
<#@ Assembly Name="IdeaBlade.EntityModel.Edm.Metadata.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="IdeaBlade.VisualStudio.DTE" #>
<#@ import namespace="IdeaBlade.VisualStudio.OM.CodeGenerator" #>
<#@ import namespace="IdeaBlade.EntityModel.Edm.Metadata" #>
<#@ include file="GetEntityParent.tt" #>
<#
 // Model1.edmx  <--- This is needed so that "Transform Related Text Templates On Save" works correctly.
 var template = new MyTestTemplate(this);
 template.Generate();
#>
<#+
 public class MyTestTemplate : DomainModelTemplate {
  public MyTestTemplate(Microsoft.VisualStudio.TextTemplating.TextTransformation textTransformation)
   :base(textTransformation) {}
   
  GetEntityParentTemplate _getEntityParentTemplate = new GetEntityParentTemplate();
 
 protected override ClassDef GetEntityClassDef(EntityOrComplexTypeWrapper wrapper)
 {    
  var _parentEntity = _getEntityParentTemplate.GetEntityParent (wrapper.Name);
    
  if (_parentEntity != null && _parentEntity != String.Empty)
  {
   // generate the current ClassDef from the passed argument
   ClassDef _classDef;
   _classDef = base.GetEntityClassDef(wrapper);
   // create a new class def instance as we're overridding it with a different base type
   // and ClassDef.BaseTypeName has a private Setter so we use the ClassDef public
   // constructor that takes Name, BaseTypeName and AccessType and then set the other properties
   ClassDef _newClassDef = new ClassDef (_classDef.Name, _parentEntity, _classDef.AccessType);
     
   // setup the remaining properties
   _newClassDef.SetAbstract (_classDef.IsAbstract);
   _newClassDef.SetNew (_classDef.IsNew);
   _newClassDef.SetPartial (_classDef.IsPartial);
   _newClassDef.SetStatic (_classDef.IsStatic);
     
   // since we're overriding the base type to be a class, I'm setting this to false
   // as I know it won't be an interface
   _newClassDef.BaseTypeIsInterface = false;
    
   // write a comment that we generated something different (useful for debugging as well)
   WriteComment("");
   WriteComment("Changed BaseTypeName to be: " + _newClassDef.BaseTypeName);
   WriteComment("");
     
   // return the new ClassDef
   return (_newClassDef);
  }
   
  // DEFAULT
  // just generate and return the normal ClassDef so all entities that just inherit directly
  // from the base injected type remain the same
  return (base.GetEntityClassDef(wrapper));
 }
   
 }
#>
 
Back to Top
orcities View Drop Down
Senior Member
Senior Member
Avatar

Joined: 28-Aug-2007
Location: United States
Posts: 454
Post Options Post Options   Quote orcities Quote  Post ReplyReply Direct Link To This Post Posted: 17-May-2010 at 11:26am
Tx. Got it working using the description as you example.
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down