locked
How can a parse the resource file of a program's assembly at run-time and find the MSL metadata for the program's EF model? RRS feed

  • Question

  • WHAT I HAVE:
    Visual Basic 2019, .NET 4.6.1, Entity Framework
    MY PROBLEM:
    Sometimes it's useful to have a program that an convert conceptual-model info (like entity/property) into corresponding store-model info (like table/column) at run-time. Most versions of EF don't directly provide the mapping data, although one can parse the XML in the MSL metadata file to resolve these relationships. My own self-made tools only work when the MSL file is a separate file copied to the "output directory", and it would nice to be able to find the necessary metadata when it's stored as a resource in the program's exe assembly. What's more, while objects exist in .NET 4.7 to recover the XML for the appropriate metadata, these objects and methods are absent in earlier .NET versions like 4.6.1--which my program needs to be built using (for reasons that aren't important here).

    I need to be able to get the resource-file info for the program's assembly (once again, at run-time), and be able to find the appropriate MSL metadata--even when my platform is pre-4.7.

    Any stuff for parsing resources in a running app's assembly--as well as stuff for extracting EF metadata from the resources--would be nice. I prefer the code examples clearly show which members should be invoked (and how) to obtain the needed info, and be written in VB.NET. Whatever is given MUST be (source-code) compatible with .NET 4.6.1 (!) and possibly lower (ideally, anything between versions 4.5 and 4.6.1 inclusive).

    Please give me a response ASAP. I've asked about this on several post and still haven't gotten a reply. (Once again, it has to a solution that can be invoked at run-time in a project configured for .NET 4.6.1!)

    PS. I've also posted this exact same request on the Developer Community (is that what it's called?), but I've only got a reference to a metadata-finder that only works for .NET 4.7. When I said I needed something that worked with earlier platforms, I got no response. I'm prepared to parse internal resources of the project's assembly and look for the metadata manually (as opposed to using a process dedicated to this particular problem), provided I know how. I'd like a simple approach to getting the resource data that I need, that doesn't require me to check several ideas and merge them together myself--since a conceptual-to-store conversion tool is intended as an ancillary, reusable utility library, rather than a full-blown project in its own rite. This is a side issue to my real project, but a necessary one all the same.


    Robert Gustafson



    Sunday, August 30, 2020 3:11 AM

All replies

  • The following code sample (in a class project) was done against EF 6 for getting all models and (meta data) several properties e.g. columns, is primary key etc. Don't remember which version of the Framework I've targeted but most likely 4.6.1 and should work 4.5 looking back at the code. Any ways I've only tested this with code first.

    On a side note, EF Core 3.x made things a good deal easier to get information on models using IProperty Interface rather than the code above uses an activator.

    A coincidence is I created a library yesterday for an blog entry using EF Core for getting model information.


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Sunday, August 30, 2020 11:31 AM
  • These “System.Data.Entity.Core and its sub-component objects” are not recognized because you need to install them via NuGet.

    For “why does it matter that the EF model is "Code First" (mine is "Model First")? A proper conversion tool should work with any kind of EF model once the model is set up”, take for instance EF Core 3.x, there were many breaking changes that in many cases if one upgraded say from EF 6 to EF Core code would break and similarly from EF Core 2.x to EF Core 3.1. Code first be it model first (which I use too) or not vs working with an .edmx there are lots of differences and .edmx is no longer supported.

    In regards to all your requirements, extremely doubtful they can be fulfilled without writing this yourself which depending on how deep down the rabbit hole you go can properly handle all cases.



    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Monday, August 31, 2020 1:35 PM
  • I got this snippet from EF6.1 Get Mapping Between Properties and Columns--converted to VB.NET--showing how to extract a table and column name from an entity and a scalar property (i.e., "AddressLine" in entity LocationSimple). What I need to know is how to modify the code to accomodate an expression for a complex property, i.e., "Address.Street.HouseNumber" in entity LocationDetail). (This code is compatible with .NET 4.6.1 [!!]; and it appears to be independent of model design [Model, Code, or Database first].)

    Option Infer On
    
    Imports System
    Imports System.Collections.Generic
    Imports System.Data.Entity
    Imports System.Data.Entity.Core.Mapping
    Imports System.Data.Entity.Core.Metadata.Edm
    Imports System.Data.Entity.Infrastructure
    Imports System.Linq
    	Friend Class Program
    
    		Public Shared Function GetColumnName(ByVal type As Type, ByVal propertyName As String, ByVal context As DbContext) As String
    			Dim metadata = DirectCast(context, IObjectContextAdapter).ObjectContext.MetadataWorkspace
    
    			' Get the part of the model that contains info about the actual CLR types
    			Dim objectItemCollection As ObjectItemCollection = (CType(metadata.GetItemCollection(DataSpace.OSpace), ObjectItemCollection))
    
    			' Get the entity type from the model that maps to the CLR type
    			Dim entityType = metadata.GetItems(Of EntityType)(DataSpace.OSpace).Single(Function(e) objectItemCollection.GetClrType(e) Is type)
    
    			' Get the entity set that uses this entity type
    			Dim entitySet = metadata.GetItems(Of EntityContainer)(DataSpace.CSpace).Single().EntitySets.Single(Function(s) s.ElementType.Name = entityType.Name)
    
    			' Find the mapping between conceptual and storage model for this entity set
    			Dim mapping = metadata.GetItems(Of EntityContainerMapping)(DataSpace.CSSpace).Single().EntitySetMappings.Single(Function(s) s.EntitySet.Equals(entitySet))
    
    			' Find the storage entity set (table) that the entity is mapped
    			Dim tableEntitySet = mapping.EntityTypeMappings.Single().Fragments.Single().StoreEntitySet
    
    			' Return the table name from the storage entity set
    			Dim tableName = If(tableEntitySet.MetadataProperties("Table").Value, tableEntitySet.Name)
    
    			' Find the storage property (column) that the property is mapped
    			Dim columnName = _
    				mapping.EntityTypeMappings.Single().Fragments.Single().PropertyMappings.OfType(Of ScalarPropertyMapping)().Single(Function(m) m.Property.Name = propertyName).Column.Name
    
    			Return tableName.ToString & "." & columnName
    		End Function
    	End Class
    The last line before Return seems to be where the change needs to be made. Since I'm not fluent in the rules for parsing a metadata workspace, could you show me what changes would be needed to get the column name for a complex-property expression (i.e., "Address.Street.HouseNumber"--dot-delimited from a "surface" property all the way down to an underlying scalar property)?

    Please give me an answer ASAP, as my model uses complex properties in some of its entities!


    Robert Gustafson


    Tuesday, September 8, 2020 3:43 AM