Living in the Tech Avalanche Generation

A practitioner’s introspective on technology

Entity Framework, IronPython and PODO’s – Can it be done? - Part 3

Before we dive into proxies when using POCO in the Entity Framework lets have a quick recap on where we left off in part 2.0.

  • Entity Framework will load PODO’s (plain old DLR Objects) fine as long as:
    • No primitives other than strings are used for fields and properties
  • Eager Loading works when ObjectQuery[T].Include() is used.
    • TSQL profiling confirms this.
  • Lazy Loading does not appear to work at all
  • Type names of materialized entities are not what are expected for runtime generated proxies.

Let’s talk about proxies a little. I wont delve too deep only enough that’s relevant to the problem at hand. Entity Framework creates proxies at runtime for our POCO entities, essentially so the framework can know the entities a vice versa, they maintain the glue so to speak. The glue is there to enable lazy loading and change tracking specifically. If you want to know more about proxies I suggest reading this post from the ADO.Net team blog. Figure 1.0 depicts debug data of a materialized proxy Entity in a C# library. Notice the unusual name of the proxy Entity in the watch window in figure 1.0 – the Entity Framework generates proxy types in the System.Data.Entity.DynamicProxies namespace.

Figure 1.0

podos_part3_proxy_vs2010

At this point, we know we are not seeing proxy type names come back when we ask our PODO for it’s full name and we are not getting any love from Lazy Loading at all. Our materialized Entities are indeed the type as engineered via __clrtype__ and we saw this when querying for the namespace of the Entity from IronPython in part 2.0.

In a nutshell, the Entity Framework is querying the database and materializing our PODO’s, however given the circumstances its reasonable to argue that no proxying is taking place and hence no lazy loading. Let’s put that theory to the test just a little more shall we! When proxies are employed in the Entity Framework there are two basic usages; proxies that support either Lazy Loading only or Change Tracking with Lazy Loading, the latter option requires all mapped properties be declared virtual and be public or protected. In Python class properties, functions and methods are considered to be as good as virtual, so we will just assume for the moment that this clears the way for the Entity Framework to work with our PODO’s as any other normal compliant class that is proxyable (of course there is no such word).

Since we are getting no proxy generation with our PODO’s then we would equally expect change tracking to fail would we not? Note in figure 1.0 that a (C#) proxy when examined has a reference to the Entity Tracker and other Entity Framework plumbing required to manage it, which we would expect to be missing if our theory about what’s happening to our PODO’s is correct. Let’s now put the whole proxy and change tracking question to rest.

def IsProxy(theType):
    ctxType = ObjectContext.GetObjectType(theType.GetType())
    notNull = theType != None
    isCtxObj = ctxType != theType.GetType();
    print \tThis entity is a %(podo)s \
                %{podo:theType.GetType()}
    print \tIt’s type in the ObjectContext is %(ctxType)s \
                %{ctxType:ctxType}
    return notNull and isCtxObj

def IsChangeTracking(podo):
    state = ctx.ObjectStateManager.GetObjectStateEntry(podo).State
    print \tIt’s state is: %(state)s % {state:state}
    return state == System.Data.EntityState.Modified

ctx.ProxyCreationEnabled  = True

parents = ctx.ParentRecords\
             .Where(it.ParentID != ‘bob’)\
             .Include(ChildRecords)

for parent in parents:
    print parent.ParentID
    parent.ParentName = change tracking works nonetheless
    isProxy = IsProxy(parent).ToString()
    isChange = IsChangeTracking(parent).ToString()
    print \tIt is %(proxy)s that this PODO is a proxy \
                %{proxy:isProxy}
    print \tIt is %(change)s that this PODO supports  \
                proxy style change tracking %{change:isChange}
    if parent.ChildRecords != None:
        for child in parent.ChildRecords:
            print \t\tChildID is :  + child.ChildID

ctx.SaveChanges()

We have added two methods, one to check if an Entity is a proxy and another to verify if change tracking is working via our proxy. Running this code produces the following TSQL, subsequent changes to the database and debug window output in NetBeans.

exec sp_executesql N‘update [dbo].[ParentRecords]
set [ParentName] = @0
where ([ParentID] = @1)
‘,N‘@0 nvarchar(50),@1 char(5)’,@0=N‘change tracking’,@1=‘FGHIJ’

podos_part3_change_track_ok

image

An interesting set of results. As suspected we have no proxies with Lazy Loading or Change tracking ability but we do have change tracking nonetheless when we get a diff from the ObjectContext. The call to .SaveChanges() on the ObjectContext is still persisting the change to the database regardless of the absence of the proxy creation.

To summarise, we now have established that loading data into PODO’s works despite producing no proxy. We can eager load only and we still have the rather large problem with natives that are not strings; this still leaves us with the little problem of this ugly message.

image

One thing that I meant to mention in one of the earlier posts is that clrtype.py does not support the use of iterables and IronPython classes in the @Accepts and @Returns decorators out of the box. Thanks to help given by Lukas Cenovsky on the IronPython mailing list who made the required changes to the validate_clr_types method in clrtype.py to get over this hurdle.

So now it’s time I thought to jump into VS 2010 and see what we can discover by checking out the dump file created by the IPY.exe crash. And that is where part 4.0 of the series will start. Until then.

Share/Save/Bookmark

1 Comment so far

  1. [...] Part 3.0 [...]

Leave a reply

Creative Commons Attribution-ShareAlike 2.5 Australia
Creative Commons Attribution-ShareAlike 2.5 Australia