| Author |
Share Topic Topic Search Topic Options
|
kimj
IdeaBlade
Joined: 09-May-2007
Posts: 1391
|
Post Options
Quote Reply
Topic: Code Second Migration Issues 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. 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;
|
 |
murray.bryant
Groupie
Joined: 11-Jan-2012
Location: Australia
Posts: 44
|
Post Options
Quote Reply
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?
|
 |
murray.bryant
Groupie
Joined: 11-Jan-2012
Location: Australia
Posts: 44
|
Post Options
Quote Reply
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
);
|
 |
murray.bryant
Groupie
Joined: 11-Jan-2012
Location: Australia
Posts: 44
|
Post Options
Quote Reply
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
|
 |
murray.bryant
Groupie
Joined: 11-Jan-2012
Location: Australia
Posts: 44
|
Post Options
Quote Reply
Posted: 07-Feb-2013 at 5:17pm |
Sorry my mistake I worked out the PathFor.
Still struggling with the PropertyMetadata though
|
 |
murray.bryant
Groupie
Joined: 11-Jan-2012
Location: Australia
Posts: 44
|
Post Options
Quote Reply
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?
|
 |
kimj
IdeaBlade
Joined: 09-May-2007
Posts: 1391
|
Post Options
Quote Reply
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]; }
|
 |
murray.bryant
Groupie
Joined: 11-Jan-2012
Location: Australia
Posts: 44
|
Post Options
Quote Reply
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)
Edited by murray.bryant - 06-Feb-2013 at 9:41pm
|
 |
murray.bryant
Groupie
Joined: 11-Jan-2012
Location: Australia
Posts: 44
|
Post Options
Quote Reply
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.
|
 |
kimj
IdeaBlade
Joined: 09-May-2007
Posts: 1391
|
Post Options
Quote Reply
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.
|
 |
murray.bryant
Groupie
Joined: 11-Jan-2012
Location: Australia
Posts: 44
|
Post Options
Quote Reply
Posted: 06-Feb-2013 at 5:16pm |
I have zipped and sent through to IdeabladeSupportTrack
There were no Ideablade* files in teh MSBuild directories
|
 |
kimj
IdeaBlade
Joined: 09-May-2007
Posts: 1391
|
Post Options
Quote Reply
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?
|
 |
murray.bryant
Groupie
Joined: 11-Jan-2012
Location: Australia
Posts: 44
|
Post Options
Quote Reply
Posted: 06-Feb-2013 at 4:25pm |
|
And yes all my references are Ideablade 7.0.3
|
 |
murray.bryant
Groupie
Joined: 11-Jan-2012
Location: Australia
Posts: 44
|
Post Options
Quote Reply
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?
Edited by murray.bryant - 06-Feb-2013 at 4:24pm
|
 |
kimj
IdeaBlade
Joined: 09-May-2007
Posts: 1391
|
Post Options
Quote Reply
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.
|
 |
murray.bryant
Groupie
Joined: 11-Jan-2012
Location: Australia
Posts: 44
|
Post Options
Quote Reply
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
|
 |