views:

378

answers:

1

Basically I want to use a dynamic data website to maintain data in an EF4 model where the entities are in their own assembly. Model and context are in another assembly.

I tried this http://stackoverflow.com/questions/2282916/entity-framework-4-self-tracking-entities-asp-net-dynamic-data-error

but get an "ambiguous match" error from reflection:

System.Reflection.AmbiguousMatchException was unhandled by user code Message=Ambiguous match found. Source=mscorlib StackTrace: at System.RuntimeType.GetPropertyImpl(String name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) at System.Type.GetProperty(String name) at System.Web.DynamicData.ModelProviders.EFTableProvider..ctor(EFDataModelProvider dataModel, EntitySet entitySet, EntityType entityType, Type entityClrType, Type parentEntityClrType, Type rootEntityClrType, String name) at System.Web.DynamicData.ModelProviders.EFDataModelProvider.CreateTableProvider(EntitySet entitySet, EntityType entityType) at System.Web.DynamicData.ModelProviders.EFDataModelProvider..ctor(Object contextInstance, Func1 contextFactory) at System.Web.DynamicData.ModelProviders.SchemaCreator.CreateDataModel(Object contextInstance, Func1 contextFactory) at System.Web.DynamicData.MetaModel.RegisterContext(Func`1 contextFactory, ContextConfiguration configuration) at WebApplication1.Global.RegisterRoutes(RouteCollection routes) in C:\dev\Puffin\Puffin.Prototype.Web\Global.asax.cs:line 42 at WebApplication1.Global.Application_Start(Object sender, EventArgs e) in C:\dev\Puffin\Puffin.Prototype.Web\Global.asax.cs:line 78 InnerException:

+1  A: 

I came across a similar problem to this recently. It had to do with inheritance in my model. I had a Resource entity that had derived types of Person, Equipment, etc. and in those I had overridden a couple properties, but by mistake gave them different signatures. I'll describe my scenario and hopefully it will help.

To be able to debug deep enough into the framework, and see all the variable values, you will have to disable optimizations:

http://blogs.msdn.com/b/kirillosenkov/archive/2009/01/27/how-to-disable-optimizations-during-debugging.aspx

I was seeing the Ambiguous Match error when registering the Context in Global.asax as you were:

    public static void RegisterRoutes(RouteCollection routes)
    {
        //                    IMPORTANT: DATA MODEL REGISTRATION 
        // Uncomment this line to register an ADO.NET Entity Framework model for ASP.NET Dynamic Data.
        // Set ScaffoldAllTables = true only if you are sure that you want all tables in the
        // data model to support a scaffold (i.e. templates) view. To control scaffolding for
        // individual tables, create a partial class for the table and apply the
        // [ScaffoldTable(true)] attribute to the partial class.
        // Note: Make sure that you change "YourDataContextType" to the name of the data context
        // class in your application. 
        DefaultModel.RegisterContext(typeof(EntityModelContainer), new ContextConfiguration() { ScaffoldAllTables = true });

Stepping into the RegisterContext method, I got to System.Web.DynamicData.ModelProviders.EFDataModelProvider there is section of code that loads all the Entities in the model by traversing the inheritance hierarchy in the constuctor for EFDataModelProvider.

while (objectStack.Any()) { EntityType entityType = objectStack.Pop(); if (entityType != null) { // Update the entity set when we are at another root type (a type without a base type). if (entityType.BaseType == null) { currentEntitySet = entitySetLookup[entityType]; }

                var table = CreateTableProvider(currentEntitySet, entityType); 
                tables.Add(table);
            } 

            foreach (EntityType derivedEntityType in derivedTypesLookup[entityType]) {
                // Push the derived entity types on the stack
                objectStack.Push(derivedEntityType); 
            }
        } 

I put a breakpoint in here and was able to see that Ambiguous Match was occurring for me when calling CreateTableProvider on my Equipment entity (which was derived from Resource).

Looking back at the Stack Trace from the original exception (which I should have done in the first place!) I put a breakpoint in the constructor for System.Web.DynamicData.ModelProviders.EFTableProvider.IsPublicProperty and watched to see which property/method/whatever was causing the ambiguous match -- for me this ended up being a navigation property called Resources (Resources are themselves a hierarchy) that I had overridden in Equipment.

  private static bool IsPublicProperty(Type entityClrType, string propertyName) {
        var property = entityClrType.GetProperty(propertyName); 
        return property != null && property.GetGetMethod() != null; 
    }

In the partial class for Equipment, I had:

public partial class Equipment
{
    public new IEnumerable<Resource> Resources
    {

but in the parent class, Resource, Resources was defined as:

    public virtual ICollection<Resource> Resources
    {

When these Properties are being loaded by the .GetProperty(propertyName) in IsPublicProperty, they have the same name but different signatures (because I had given them different return type by mistake) so it isn't clear which shoudl be loaded based on name alone. I corrected my mistake and made Resources in my Equipment class return an ICollection, and boom -- no more ambiguous match.

Not sure if this will help or not, but if you step through in a similar way you should be able to find exactly what is causing the ambiguous match.

adamnickerson