beaucrawford.net

Give me data or give me death

About the author

Author Name is someone.
E-mail me Send mail

Recent comments

Don't show

Authors

Tags

Don't show

    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

    © Copyright 2012

    Entity Framework Detached Instances

    When working with the Entity Framework you will often find yourself working with a detached Entity instance (working with Entities over a WCF service or perhaps using them as part of an n-tier architecture).  Before you can perform any data access operations dealing with this Entity you must first attach it to an ObjectContext.  This, as you might expect, is slightly more complicated than simply calling ObjectContext.Attach.

    Thankfully, the ObjectContext class has a method named “ApplyPropertyChanges”.  Calling it is pretty straightforward, as shown below in the AttchUpdated method.   It’s never that simple though is it?  It took me awhile to realize that this method only works with Scalar property types.  As stated on MSDN:

    ApplyPropertyChanges does not affect navigation properties or related objects.

    This ended up being a major show stopper for me until I figured it out.  It turns out that, for properties that are EntityReference instances, i.e. Navigation properties, you must query the Entity’s RelationshipManager (see the ApplyReferencePropertyChanges method).

     

    public static void LoadMetadataFromAssembly(this ObjectContext context)
    {
        context.MetadataWorkspace.LoadFromAssembly(context.GetType().Assembly);
    }
    
    public static void AttachUpdated(this ObjectContext context, EntityObject detachedEntity)
    {
        if (detachedEntity.EntityState == EntityState.Detached)
        {
            object currentEntity = null;
    
            if (context.TryGetObjectByKey(detachedEntity.EntityKey, out currentEntity))
            {
                context.ApplyPropertyChanges(detachedEntity.EntityKey.EntitySetName, detachedEntity);
    
                var newEntity = detachedEntity as IEntityWithRelationships;
                var oldEntity = currentEntity as IEntityWithRelationships;
    
                if (newEntity != null && oldEntity != null)
                {
                    context.ApplyReferencePropertyChanges(newEntity, oldEntity);
                }
            }
            else
            {
                throw new ObjectNotFoundException();
            }
        }
    }
    
    private static void ApplyReferencePropertyChanges(this ObjectContext context, IEntityWithRelationships newEntity, IEntityWithRelationships oldEntity)
    {
        foreach (var relatedEnd in oldEntity.RelationshipManager.GetAllRelatedEnds())
        {
            var oldReference = relatedEnd as EntityReference;
    
            if (oldReference != null)
            {
                var newReference = newEntity.RelationshipManager.GetRelatedEnd(oldReference.RelationshipName, 
                    oldReference.TargetRoleName) as EntityReference;
    
                if (newReference != null)
                {
                    oldReference.EntityKey = newReference.EntityKey;
                }
            }
        }
    }

    Example:

    Product product = SomeProduct();
    
    using (var context = new BuyMoreStuffEntities())
    {
        context.LoadMetadataFromAssembly();
        context.AttachUpdated(product);
        context.SaveChanges();
    }

    Categories: Entity Framework
    Posted by Beau on Monday, March 09, 2009 8:35 PM
    Permalink | Comments (0) | Post RSSRSS comment feed

    Entity Framework - Generating SSDL, CSDL, and MSL

    If you do not want to use the Visual Studio designer to generate your Entity Framework schema files you can use edmgen instead.  I spent some time poking around this application in Reflector and found out what’s involved.  You can use this code to generate the Entity Framework schema files directly yourself.

    Note: You will first need to reference the "System.Data.Entity.Design" assembly and namespace.

    Generating the SSDL file:

    const string Provider = "System.Data.SqlClient";
    const string ConnectionString = "server=.;database=MyDatabase;integrated security=true;";
    const string Namespace = "Testing";
    
    var generator = new EntityStoreSchemaGenerator(Provider, ConnectionString, Namespace);
    generator.GenerateStoreMetadata();
    generator.WriteStoreSchema(@"D:\temp\storeSchema.ssdl");
    var storeEntityContainer = generator.EntityContainer;

    Generating the CSDL and MSL files:
    const string Namespace = "Testing";
    const string ContainerName = "MyContainer";
    
    EntityModelSchemaGenerator generator = new EntityModelSchemaGenerator(storeEntityContainer, Namespace, ContainerName);
    generator.GenerateMetadata();			
    generator.WriteModelSchema(@"D:\temp\modelSchema.csdl");
    generator.WriteStorageMapping(@"D:\temp\storageMapping.msl");


    Generate Classes:

    private static void GenerateObjectLayerCode(string csdlFile, IEnumerable additionalSchemas)
    {
    	var generator = new EntityClassGenerator(LanguageOption.GenerateCSharpCode);
    	var reader = XmlReader.Create(csdlFile);
    	var writer = new StringWriter();
    	generator.GenerateCode(reader, writer, additionalSchemas);
    	string code = writer.GetStringBuilder().ToString();
    }

    The disappointment is that the extensibility for generating the classes in the last step is extremely limited. You only have two options – implement event handlers that fire when a Type and/or Property is created.  The problem is that the TypeGeneratedEventArgs and PropertyGeneratedEventArgs classes passed to your event handler are extremely limited.  For the properties you are not passed the entire CodeDOM CodeMemberProperty instance.  Instead you are only allowed to add additional get/set statements.  You have no way of completely customizing the property definition. In a future post I plan to explore the usage of NRefactory to accomplish this.

    Posted by Beau on Saturday, February 21, 2009 3:00 PM
    Permalink | Comments (2) | Post RSSRSS comment feed