Search code examples
c#razor.net-coreasp.net-mvc-scaffolding

Get RelatedEntities from ModelMetaData in .Net Core 1.1


I have tried to get the Related Entities in .Net Core in a scaffolding context.

I am building a Details page in MVC that is being scaffolded. I need the Properties and Navigations. All the relevant properties are being shown, however, only the non-ICollection navigation properties are shown from .Navigations.

The object being loaded is Microsoft.VisualStudio.Web.CodeGeneration.EntityFrameworkCore.ModelMetaData

foreach (var property in Model.ModelMetadata.Properties)
{
    if (property.Scaffold && !property.IsPrimaryKey && !property.IsForeignKey)
    {
        <dt>
            @@Html.DisplayNameFor(model => model.@GetValueExpression(property))
        </dt>
        <dd>
            @@Html.DisplayFor(model => model.@GetValueExpression(property))
        </dd>
    }
}
foreach (var navigation in Model.ModelMetadata.Navigations)
{
    <dt>
        @@Html.DisplayNameFor(model => model.@GetValueExpression(navigation))
    </dt>
    <dd>
        <a asp-area="" @GetNavigationLinkExpression(navigation)>@@Html.DisplayFor(model => model.@GetValueExpression(navigation)[email protected])</a>
    </dd>
}

My model is as such... and the ModelMetaData can only navigate through the second and skips the first. Where can I get access to the first property here so that I can template it?

public virtual ICollection<SomeModel> CollectionNavigationProperty1 { get; set; }
public virtual AnotherSomeModel NavigationProperty1 { get; set; }

Solution

  • Well, after a few hours of trying, I managed to produce a workaround that's nowhere near as dynamic as I'd have liked. I just can't figure out how to get the Type objects of the entity Model.

    You can get a list of ICollection objects as follows:

    var icollections = new List<string>();
    
    foreach (PropertyInfo property in
        typeof(YourProjectName.ContextObject).Assembly
        .GetType("YourProjectName.Entities." + Model.ModelTypeName)
        .GetProperties())
    {
        if (property.PropertyType.IsGenericType 
            && property.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>))
        {
            icollections.Add(property.Name);
        }
    }
    

    Replace 'YourProjectName.ContextObject' with the full namespace and classname of your DbContext object. Replace 'YourProjectName.Entities.' with the full namespace of where your entities will be.

    This will only work properly if your Entities / Models are kept in the same namespace.

    Hopefully somebody can provide a better solution but this will be what I use for now.