Print Page | Close Window

Code Second Migration Issues

Printed From: IdeaBlade
Category: DevForce
Forum Name: DevForce 2012
Forum Discription: For .NET 4.5
URL: http://www.ideablade.com/forum/forum_posts.asp?TID=3980
Printed Date: 12-May-2026 at 11:00pm


Topic: Code Second Migration Issues
Posted By: murray.bryant
Subject: Code Second Migration Issues
Date Posted: 05-Feb-2013 at 11:31pm
Hi

I am trying to migrate an existing project across to code-first.

I have followed the steps from the documentation

- Change Template to CodeFirst and Save
- Add nuget code-first package
- Create new Model.cs file copy pocos to file
- Delete old EDMX
- Change Connection String

When I then build the project nothing happens. No ibmmx is generated

in the output

>------ Build started: Project: Torpedo.Geo.Model, Configuration: Debug Any CPU ------
1>Build started 6/02/2013 3:30:06 PM.
1>RestorePackages:
1>  "C:\Development\Torpedo.Geo\.nuget\nuget.exe" install "C:\Development\Torpedo.Geo\Torpedo.Geo.Model\packages.config" -source ""  -RequireConsent -solutionDir "C:\Development\Torpedo.Geo\ "
1>  All packages listed in packages.config are already installed.
1>PostSharp21InspectReferences:
1>  Detected reference to 'PostSharp'.
1>GenerateTargetFrameworkMonikerAttribute:
1>Skipping target "GenerateTargetFrameworkMonikerAttribute" because all output files are up-to-date with respect to the input files.
1>CoreCompile:

I can't see devforce trying to generate the metadata

I am kind of stuck here.  Any suggestions would be appreciated

thanks

Murray





Replies:
Posted By: kimj
Date Posted: 06-Feb-2013 at 9:48am
Make sure that it was the DevForce 2012 Code First NuGet package that you installed - we also have a similar package for DF2010.  You can also check that the package installed correctly by looking at the project file contents.  Here's a link showing what to look for:  http://drc.ideablade.com/devforce-2012/bin/view/Documentation/code-first-entity-classes#HInstallDevForceCodeFirstsupport - http://drc.ideablade.com/devforce-2012/bin/view/Documentation/code-first-entity-classes#HInstallDevForceCodeFirstsupport
 
If the package is installed but the problem persists, turn up the verbosity of the MSBuild output to "normal" or higher (via the VS Tools menu) to see if anything shows up during the build.
 


Posted By: murray.bryant
Date Posted: 06-Feb-2013 at 3:33pm
Yes it is 2012 that is installed

the project seems to be installed

 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <Import Project="$(SolutionDir)\.nuget\nuget.targets" />
  <Import Project="..\packages\PostSharp.2.1.7.28\tools\PostSharp.targets" Condition="Exists('..\packages\PostSharp.2.1.7.28\tools\PostSharp.targets')" />
  <Import Project="..\packages\IdeaBlade.DevForce.Aop.7.0.3\tools\IdeaBlade.DevForce.Common.targets" Condition="Exists('..\packages\IdeaBlade.DevForce.Aop.7.0.3\tools\IdeaBlade.DevForce.Common.targets')" />
 

I already posted the result from the normal msbuild. Looking through the verbose setting is hard to spot anything. Can you post what should be showing in the build. Or something I can search for in the output.

thanks

Murray


Posted By: kimj
Date Posted: 06-Feb-2013 at 4:08pm
The "EntityModelMetadataDeploy" task should be showing up in the MSBuild output, but then it will also raise build warnings and errors when it encounters problems, and these would be hard to miss.
 
Do you also have DF2010 installed?  If so, double check that all IdeaBlade assembly references are pointing to version 7.0.3.  If you have a version of DF2010 prior to 6.1.9 that will cause problems too, as side-by-side installations of both products are only supported with 6.1.9 and above.


Posted By: murray.bryant
Date Posted: 06-Feb-2013 at 4:15pm
I uninstalled all of my devforce 2010 a while back

In the detailed log for the model project build there is no mention of EntityModelMetadataDeploy

what could be causing this?


Posted By: murray.bryant
Date Posted: 06-Feb-2013 at 4:25pm
And yes all my references are Ideablade 7.0.3


Posted By: kimj
Date Posted: 06-Feb-2013 at 5:02pm
We've seen some issues with the DevForce 2010 uninstall not cleanly removing MSBuild targets.  Check your \program files (x86)\MSBuild\v4.0 folder for an IdeaBlade.*.targets file and remove it if found.  There might also be an IdeaBlade folder under the MSBuild folder, and that can be removed too.
 
If that's not causing the problem, can you zip up the project in question and either upload here or send to our IdeaBladeSupportTrack email address?


Posted By: murray.bryant
Date Posted: 06-Feb-2013 at 5:16pm
I have zipped and sent through to IdeabladeSupportTrack

There were no Ideablade* files in teh MSBuild directories


Posted By: kimj
Date Posted: 06-Feb-2013 at 7:17pm
Does this project actually build successfully?  The ibmmx metadata file is only created if the assembly can be built without errors, as the EntityModelMetadataDeploy task kicks in after a successful compilation.
 
I notice that the ProvideEntityAspect attribute is specified on both the base and derived classes, which is one problem.  There are also some constructs in use, such as PathFor and PropertyMetadata, which aren't defined for Code First entities.
 
Once you fix the build problems the metadata files should generate.


Posted By: murray.bryant
Date Posted: 06-Feb-2013 at 8:19pm
The project worked fine when using the EDM

As you say what I seem to be running into is the functionality that is not present in code-first that is there for the edm use.

It would be nice if these differences were documented somewhere. Do you know where such a resource is?

I will work through the rest of the build errors. I guess I was hoping some of these would disappear once the ibmmx process occurred. But it seems that was wrong.




Posted By: murray.bryant
Date Posted: 06-Feb-2013 at 9:31pm
Originally posted by kimj

 There are also some constructs in use, such as PathFor and PropertyMetadata, which aren't defined for Code First entities.


These are both generated by devforce in the EDM version. Do you have any code that I could add to a base class that replicates this functionality?

PropertyMetadata and pathfor I use extensively for verifiers. ( as per your documenation)


Posted By: kimj
Date Posted: 07-Feb-2013 at 11:20am
Sorry, we don't currently have any documentation describing how to move an EDMX-based model to Code First.
 
In the EDMX-generated code, you'll see the PathFor method generated for every entity class like so:
 
 public static string PathFor(System.Linq.Expressions.Expression<System.Func<Employee, object>> expr) {
   return IbCore.PropertyPath.For<Employee>(expr);
 }
 
You have several options for how you handle this:  one would be to directly call the IdeaBlade.Core.PropertyPath method instead of using PathFor; another would be to include this helper method in your entity class definitions; and another might be to include this in a base or helper class as a generic method: 
 
public static string PathFor<T>(System.Linq.Expressions.Expression<System.Func<T, object>> expr) {
  return PropertyPath.For<T>(expr);
}
 
The PropertyMetadata is a bit different.  In EDMX-based models PropertyMetadata is a nested class within each entity holding the static data property definitions for the entity.  In a Code First model, all metadata is dynamically loaded from the ibmmx file, and is available in the EntityMetadataStore.  
 
So again you should decide how best to architect this in your solution.  You can access metadata for an entity like so:
 
  public static EntityMetadata PropertyMetadata {
    get { return EntityMetadataStore.Instance.GetEntityMetadata(typeof(Employee)); }
  }
 
Entity properties are available from the EntityMetadata in several ways, for example:
   Employee.PropertyMetadata.EntityProperties
   Employee.PropertyMetadata.DataProperties
   Employee.PropertyMetadata.NavigationProperties
   ... and others
 
So you might have a simple helper method like the following:
  public static EntityProperty GetPropertyMetadata(string prop) {
    return PropertyMetadata.EntityProperties[prop];
  }
 
More information on the metadata available is here - http://drc.ideablade.com/devforce-2012/bin/view/Documentation/model-examine - http://drc.ideablade.com/devforce-2012/bin/view/Documentation/model-examine .
 
 
  
 


 
 


Posted By: murray.bryant
Date Posted: 07-Feb-2013 at 5:09pm
Thanks for the reply

I am still struggling with this.

I am trying to implement a cross type verifier.

<quote>
private static Verifier GetOrderDateAfterHiredVerifier() {

string description =
  "OrderDate must be after the sales rep's HireDate.";
  DelegateVerifier<Order> v = new DelegateVerifier<Order>(
      description, OrderDateAfterHiredCondition);

  v.VerifierOptions.ExecutionModes =
    VerifierExecutionModes.InstanceAndOnAfterSetTriggers;

  v.AddTrigger(Order.PathFor(o => o.OrderDate));
  v.AddTrigger(new TriggerLink(new TriggerItem
    (typeof(Employee), Employee.PathFor(e => e.HireDate)),
    e => ((Employee)e).Orders,
  // Path from trigger (Employee) to Order
  true));   // True = that path returns multiple orders
return v;
}
</quote>

and that code you provided does not work for the PathFor in this example ( copied from your documentation). Do you have any examples of verifiers working in code-first implementations?







Posted By: murray.bryant
Date Posted: 07-Feb-2013 at 5:17pm
Sorry my mistake I worked out the PathFor.

Still struggling with the PropertyMetadata though


Posted By: murray.bryant
Date Posted: 07-Feb-2013 at 5:27pm
So for adding a trigger

 v.AddTriggers(
                
                Lithology.PropertyMetadata.IntervalFrom.Name,
                Lithology.PropertyMetadata.IntervalTo.Name);

I can access the PropertyMetadata by adding your previous code

 public static IbEm.EntityMetadata PropertyMetadata
        {
            get { return IbEm.EntityMetadataStore.Instance.GetEntityMetadata(typeof(Lithology)); }
        }

to the Lithology Class.

However I an unsure as to how to access the property name that the addtrigger code needs.

thanks for you help


Posted By: murray.bryant
Date Posted: 07-Feb-2013 at 5:39pm
Ok it seems I can do the following
 v.AddTriggers(
               Sample.EntityPropertyNames.SampleType_id,
               Sample.EntityPropertyNames.Standard_id

               );





Posted By: murray.bryant
Date Posted: 07-Feb-2013 at 6:42pm
My next issue is that the entities no longer have Ideablade.EntityModel.Entity as a base class

Which means I am having issues with things like cloning.

I currently use


 public static T Clone<T>([NotNull] this T source, int level = 0) where T : Entity
        {
            if (source == null) throw new ArgumentNullException("source");
            var handledEntities = new Dictionary<Entity, Entity>();
            return source.InternalClone(level, handledEntities);
        }

        private static T InternalClone<T>([NotNull] this T source, int level, IDictionary<Entity, Entity> handledEntities) where T: Entity
        {
            var res = (source as ICloneable).Clone() as T;
            handledEntities[source] = res;
            if (level > 0)
            {
                foreach (var pi in source.GetType().GetProperties().Where(pi => pi.CanRead))
                {
                    if (pi.PropertyType.IsChildOf(typeof(RelatedEntityList<>)))
                    {
                        var sList = pi.GetValue(source, null) as IList;
                        var list = pi.GetValue(res, null) as IList;
                        if (sList != null && list != null)
                        {
                            foreach (Entity item in sList)
                            {
                                var cItem = handledEntities.ContainsKey(item)
                                                ? handledEntities[item]
                                                : item.InternalClone(level - 1, handledEntities);
                                list.Add(cItem);
                            }
                        }
                    }
                    else if (pi.CanWrite && pi.PropertyType.IsSubclassOf(typeof(Entity)))
                    {
                        var sInstance = pi.GetValue(source, null) as Entity;
                        if (sInstance != null)
                        {
                            var clonedEntity = handledEntities.ContainsKey(sInstance)
                                                ? handledEntities[sInstance]
                                                : sInstance.InternalClone(level - 1, handledEntities);
                            pi.SetValue(res, clonedEntity, null);
                        }
                    }
                }
            }
            return res;
        }

Do you have any advice on how I can now hande this?




Posted By: kimj
Date Posted: 07-Feb-2013 at 7:20pm
Since you have control over your Code First entity class definitions, one option is to implement ICloneable in code.
 
A back door of a sort is to take advantage of the fact that Code First entities do have an injected EntityAspect, which you normally don't want to expose directly, but instead use something like an "EntityFacts" class as described here - http://drc.ideablade.com/devforce-2012/bin/view/Documentation/code-first-entityaspect#HEntityFacts - http://drc.ideablade.com/devforce-2012/bin/view/Documentation/code-first-entityaspect#HEntityFacts .  Anyway, EntityAspect.CloneCore() will clone the entity.  There's one problem here, though, in that this clone will have an incorrect EntityState which you'll need to reset.  Here's a rough way to do it:
 
  var clone = EntityAspect.Wrap(anEntity).CloneCore().Entity as IEntity;
  clone.EntityAspect.EntityState = EntityState.Detached;
 



Print Page | Close Window