Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to build EDM model for OData Web API in runtime?

I have a case when my entities that I need to expose through OData are completely dynamic (e.g., user can configure which fields he wants to expose). Query results from repository are stored in special generic class that has a dictionary for actual data (FieldName/Value), so CLR type is one for all. I have complete knowledge about the entity (entity name, entity fields and their types).

Because of that I can't build EDM model in design-time using ODataModelBuilder methods like Entity, EntitySet or HasKey(), Property() from EntityTypeConfiguration.

Is it possible to build EDM model from scratch? ODataModelBuilder uses EntityTypeConfiguration, but it depends on CLR type of entity. Basically I need to declare several entity types with one CLR type for all of them.

Please advise.

like image 614
Vladimir Panchenko Avatar asked Jan 28 '15 19:01

Vladimir Panchenko


2 Answers

Ok, so I've figured out an answer to this problem.

I've written my own OData model builder that uses types from Microsoft.Data.Edm.Library namespace (EdmModel, EdmEntityType and so on).

Example:

public IEdmModel GetEdmModel()
{
    EdmModel model = new EdmModel();

    EdmEntityContainer container = new EdmEntityContainer(Namespace, "DefaultContainer");
    model.AddElement(container);
    model.SetIsDefaultEntityContainer(container, isDefaultContainer: true);

    EdmEntityType edmType = new EdmEntityType(Namespace, "Foo");
    EdmStructuralProperty idProp = edmType.AddStructuralProperty("Id", EdmCoreModel.Instance.GetPrimitiveType(EdmPrimitiveTypeKind.Int32), false);
    edmType.AddKeys(idProp);

    сontainer.AddEntitySet("MyEntitySet", edmType);

    model.SetDataServiceVersion(new Version(3, 0, 0, 0));
    model.SetMaxDataServiceVersion(new Version(3, 0, 0, 0));

    return model;
}
like image 116
Vladimir Panchenko Avatar answered Sep 27 '22 23:09

Vladimir Panchenko


I solved this problem like that,

private static IEdmModel GetEdmModel()
{
    ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
    builder.Namespace = "WebAPI";
    builder.ContainerName = "DefaultContainer";
    builder.EnableLowerCamelCase();

    foreach (Type item in GetTypesInNamespace(System.Reflection.Assembly.Load("ProjectDLL"), "NamespaceOfModels"))
    {
        //My models have a key named "Id"
        if (item.GetProperty("Id") == null)
            continue;

        EntityTypeConfiguration entityType = builder.AddEntityType(item);
        entityType.HasKey(item.GetProperty("Id"));
        builder.AddEntitySet(item.Name,entityType);
    }

    return builder.GetEdmModel();
}

Getting types in Sample Namespace

private static Type[] GetTypesInNamespace(System.Reflection.Assembly assembly, string nameSpace)
{
    return assembly.GetTypes()
        .Where(t => String.Equals(t.Namespace, nameSpace, StringComparison.Ordinal))
        .ToArray();
}
like image 42
ahmeticat Avatar answered Sep 28 '22 01:09

ahmeticat