如何在运行时为 OData Web API 构建 EDM 模型?

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

我有一个案例,我需要通过 OData 公开的实体是完全动态的(例如,用户可以配置他想要公开的字段)。来自存储库的查询结果存储在具有实际数据字典 (FieldName/Value) 的特殊泛型 class 中,因此 CLR 类型是通用的。我完全了解实体(实体名称、实体字段及其类型)。

因此,我无法在设计时使用 Entity、EntitySet 或 HasKey() 等 ODataModelBuilder 方法构建 EDM 模型,属性() 来自 EntityTypeConfiguration。

是否可以从头开始构建 EDM 模型? ODataModelBuilder 使用 EntityTypeConfiguration,但它取决于实体的 CLR 类型。基本上我需要用一种 CLR 类型声明几种实体类型。

请指教

好的,所以我找到了这个问题的答案。

我编写了自己的 OData 模型构建器,它使用来自 Microsoft.Data.Edm.Library 命名空间的类型(EdmModel、EdmEntityType 等)。

示例:

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

我就这样解决了这个问题,

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

获取示例命名空间中的类型

private static Type[] GetTypesInNamespace(System.Reflection.Assembly assembly, string nameSpace)
{
    return assembly.GetTypes()
        .Where(t => String.Equals(t.Namespace, nameSpace, StringComparison.Ordinal))
        .ToArray();
}