none
Two Problems after upgrade to .NET 4

    Question

  • Hi all.

    I'm having two issues after upgrade from V3.5 SP1 TO v4.

    The first is that my precompile throws an error about V2.xxx and V4 not being compatible even though the object that it's trying to initialize is in the same dll. I updated the efgen command to the right output directory but no joy. Anyone have any incite on the changes to getting EF to precompile?

     

    The second is that I had this nifty little function:

            public static TradepointContainer GetDataContext(this IEntityWithRelationships entity) {
                if (entity == null)
                    throw new ArgumentNullException("entity");            
    
                object DataContext = entity.RelationshipManager.GetType().InvokeMember("_context", System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic, null, entity.RelationshipManager, null);
    
                if (DataContext != null)
                    return (TradepointContainer)DataContext;
    
                var relationshipManager = entity.RelationshipManager;
    
                var relatedEnd = relationshipManager.GetAllRelatedEnds()
                                                    .FirstOrDefault();
    
                if (relatedEnd == null)
                    throw new Exception("No relationships found");
    
                var query = relatedEnd.CreateSourceQuery() as ObjectQuery;
    
                if (query == null)
                    throw new Exception("The Entity is Detached");
    
                return (TradepointContainer)query.Context;
            }
    

    That used to work like a charm, to get the context that an object was connected to if any. Of course the reflected property no longer exists :<

    Anyone have a work around so that I can have an object and get it's context when it isn't known with V4???

    Thanks!

    Saturday, April 10, 2010 12:35 AM

Answers

  • Hi John,

    Thanks for taking the time to explain why you need to do this.

    Just to give you some background, from the perspective of the Entity Framework, the assumption that there is an ObjectContext (and only one) associated with each entity has always been an implementation detail and never intended to be part of the contract, therefore we intentionally don't provide a direct way to access the context from an entity using the public API. Conceptually, the association between ObjectContexts and entities is better understood as going in the opposite way: ObjectContexts track entities.

    In fact, after we released in .NET 3.5 SP1, many customers gave us the feedback that their scenarios required the ability to move entities that were obtained from one context to another context, so in EF 4 we worked to make that possible, not only for Self-Tracking Entities but for the default EntityObject-based entities and for basic POCOs. In the particular case of basic POCOs, nothing prevents you from tracking the same entity instance in multiple ObjectContexts simultaneously.

    All that said, the assumption might be valid from your application’s perspective, and EF 4 actually provides the necessary hooks to help you make your entities work that way.

    Here are a few steps you can follow:

    Step 1: Define an interface for entities that have a Context property:

        public interface IEntityWithContext

        {

            ObjectContext Context { get; set; }

        }

     

    Step 2: Implement this interface in all your entities (i.e. manually, using partial classes, or changing the T4 template used for code generation):

        public partial class Blog : IEntityWithContext

        {

            System.Data.Objects.ObjectContext IEntityWithContext.Context { get; set; }

        }

     

    Step 3: Setup the ObjectMaterialized event in the ObjectContext to set the context instance on all entities at materialization time:

        this.ObjectMaterialized +=
            (entity, _) => ((IEntityWithContext)entity).Context = this;

     

    Step 4: Rewrite your method to obtain a strongly typed context from an entity like this:

     

        public static BloggingContainer GetAssociatedContext(object entity)

        {

            var entityWithContext = entity as IEntityWithContext;

            return (entityWithContext == null) ? null :
                (BloggingContainer)entityWithContext.Context;

            }

     

    Of course, there are many variations you can choose from, depending among other things on whether you want the context property to actually show in your entities (in which case you can make the implementation of the interface implicit) or rather hide this an implementation detail of your data access layer.

     

    Hope this helps,

    Diego

    Sunday, April 11, 2010 12:37 AM
    Moderator

All replies

  • Hi John,

    I am not sure about the first issue. It really sounds like you are trying to execute the wrong version of the program.

    Regarding the second issue, your code allready includes an anternative way to obtain the context that is not dependent on reflection:

        relatedEnd.CreateSourceQuery().Context

    I would recommend to just comment out the code that tries using reflection and let the second method kick in. The truth is that method is not going to work always, and it is relatively expensive, but it is safer than leaving that depending on reflection.

    All that said, I would encourage you to if possible not depend on the ability to obtain an ObjectContext instance from an entity. There are cases in which this is not going to be possible anyway (i.e. with POCO entities), and besides, whatever reason you are doing it now, there is usually another way... Can you please ellaborate on what you are using the context for and you you cannot pass it in some other way?

    Hope this helps,
    Diego


    This posting is provided "AS IS" with no warranties, and confers no rights.
    Saturday, April 10, 2010 5:11 AM
    Moderator
  • The reason why I do it is because the entities in V1 were tied to a specific object context, and you couldn't share across them. Hence there are a ton of cases where I needed to do business logic and get other objects and attach them in response to events (i.e. a product would change on an invoice detail line, which would cause a recalc of the taxes on the base invoice, which would then result in a new sales tax being added to the invoice, because it's applicable to that product, and not the other products in the invoice so I would have to go out and get the sales tax and attach it).

    This is pretty standard business process that I'm talking about, and it happens all of the time, especially in accounting where rules change based on the events.

    If self-tracking entities mean that I can share contexts then this is a non-issue, however it seems to me, that every entity should have a context property that you can get since there is a reference somewhere.

    The reflection method, while not hugely fast was WAY faster than the secondary method and more reliable because every object that was attached would get a context.

     

    As for the first issue, it sounds like it, but it only happens if you efgen the pre-compiled versions of the entities (for speed). If you let it embed and compile on first run, then it's fine. Anyone gotten pre-compile to work in EF4?

    Saturday, April 10, 2010 11:00 AM
  • BTW, here's the full error for #1: Mixed mode assembly is built against version 'v2.0.50727' of the runtime and cannot be loaded in the 4.0 runtime without additional configuration information.
    Saturday, April 10, 2010 11:02 AM
  • Hi John,

    Thanks for taking the time to explain why you need to do this.

    Just to give you some background, from the perspective of the Entity Framework, the assumption that there is an ObjectContext (and only one) associated with each entity has always been an implementation detail and never intended to be part of the contract, therefore we intentionally don't provide a direct way to access the context from an entity using the public API. Conceptually, the association between ObjectContexts and entities is better understood as going in the opposite way: ObjectContexts track entities.

    In fact, after we released in .NET 3.5 SP1, many customers gave us the feedback that their scenarios required the ability to move entities that were obtained from one context to another context, so in EF 4 we worked to make that possible, not only for Self-Tracking Entities but for the default EntityObject-based entities and for basic POCOs. In the particular case of basic POCOs, nothing prevents you from tracking the same entity instance in multiple ObjectContexts simultaneously.

    All that said, the assumption might be valid from your application’s perspective, and EF 4 actually provides the necessary hooks to help you make your entities work that way.

    Here are a few steps you can follow:

    Step 1: Define an interface for entities that have a Context property:

        public interface IEntityWithContext

        {

            ObjectContext Context { get; set; }

        }

     

    Step 2: Implement this interface in all your entities (i.e. manually, using partial classes, or changing the T4 template used for code generation):

        public partial class Blog : IEntityWithContext

        {

            System.Data.Objects.ObjectContext IEntityWithContext.Context { get; set; }

        }

     

    Step 3: Setup the ObjectMaterialized event in the ObjectContext to set the context instance on all entities at materialization time:

        this.ObjectMaterialized +=
            (entity, _) => ((IEntityWithContext)entity).Context = this;

     

    Step 4: Rewrite your method to obtain a strongly typed context from an entity like this:

     

        public static BloggingContainer GetAssociatedContext(object entity)

        {

            var entityWithContext = entity as IEntityWithContext;

            return (entityWithContext == null) ? null :
                (BloggingContainer)entityWithContext.Context;

            }

     

    Of course, there are many variations you can choose from, depending among other things on whether you want the context property to actually show in your entities (in which case you can make the implementation of the interface implicit) or rather hide this an implementation detail of your data access layer.

     

    Hope this helps,

    Diego

    Sunday, April 11, 2010 12:37 AM
    Moderator
  • Hi John,

     

    I am writing to check the status of the issue on your side.  Would you mind letting us know the result of the suggestions? 

     

    If you need further assistance, please feel free to let me know.   I will be more than happy to be of assistance.

     

    Have a nice day!

     

     

    Best Regards,
    Lingzhi Sun

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Tuesday, April 20, 2010 1:27 AM
    Moderator
  • For right now I dove in further into the reflection and found it on the new hidden classes, but I'm definately going to go down the route of implimenting the event and keeping it there in the object going forward.

     

    The RTM version fixed the issue with the pre-compile without me having to do anything more so I think I'm good to go.... except for the Winforms designer which is even more broken then VS.net 2008 and that's saying something! (but that's for a different forum :)

    Thanks for everyone's help!

    Thursday, April 22, 2010 1:54 AM