9
votes

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.

2

2 Answers

11
votes

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;
}
2
votes

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();
}