locked
Get Metadata RRS feed

  • Question

  •  

    Given a model say "MyEntities" how can I get the metadata for a specific column maxlength.

     

    The csdl contains the following:

     

    Code Snippet

    <EntityType Name="Location">
        <Key>
          <PropertyRef Name="LocationID" />
        </Key>
        <Property Name="LocationID" Type="Guid" Nullable="false" />
        <Property Name="Name" Type="String" Nullable="false" MaxLength="50" Unicode="false" FixedLength="false" />
    </EntityType>

     

     

    I want to get the MaxLength=50 value programmatically given my MyEntities context.

     

    Looks like something along the lines of:

     

    Code Snippet

    var csdl = new MyEntities().MetadataWorkspace.GetItemCollection(System.Data.Metadata.Edm.DataSpace.CSpace);

     

     

     

    But where to go from there? or is there a better way? I am not sure what to look for within the ItemCollection. Specifics if possible.

     

    Thanks in advance for any help.

     

    -Andy

    Wednesday, August 13, 2008 6:22 PM

Answers

  • Hi Andy

     

    Yes, I suppose a sneak peek of my book would have been useful after all. ;-)

     

    That only gives you the GetItemCollection.

     

    Look at the GetItem or TryGetItem methods. TryGetItem is safer, but GetItem is easier to type from the top of my head without intellisense helping Especially when using CSL  (C# as a second language). I'm definitely not worrying about a null value being thrown in this example.

     

    Code Snippet

    var myTypes= mdw.GetItem<EntityType)("insertmodelnamehere.Location",DataSpace.CSpace);

    var myprop=(from prop in myTypes where prop.Name=="Name" select prop).First

    //now drill in further to the TypeUsage property then you can find all of teh facets

    var facets=myprop.TypeUsage.Facets

    //iterate through the facets to find your maxlength

     

     

    The debugger is your friend here. THere's a lot of info in there.

     

    hth

    julie

    Wednesday, August 13, 2008 9:55 PM
  • Julie,

     

    I came up with a slightly different solution. I don't have to pass in the model name in addition to the context class name and entity name but run the risk of the context containing more than one name of typeName. I do wonder if there is a way to get at the csdl without firing up a copy of the context class? But realize that the xml could be in a number of different places (either resource or xml in the bin).

     

    So this is almost as funny as communicating via facebook....

     

    Thanks much for the help. You definately got me going in the right direction.

     

    -Andy

     

    Code Snippet

    private int GetFacetValue(string entityName, string typeName, string propertyName)

    {

    var context = (ObjectContext)Activator.CreateInstance(BuildManager.GetType(entityName, true));

    var csdl = context.MetadataWorkspace.GetItemCollection(DataSpace.CSpace);

    var entity = csdl.GetItems<EntityType>().Where(e => e.Name == typeName).SingleOrDefault();

    var property = entity.Properties.Where(p => p.Name == propertyName).SingleOrDefault();

    var facet = property.TypeUsage.Facets.Where(f => f.Name == "MaxLength").SingleOrDefault();

    }

     

     

     

     

    Wednesday, August 13, 2008 11:07 PM

All replies

  • Hi Andy

     

    Yes, I suppose a sneak peek of my book would have been useful after all. ;-)

     

    That only gives you the GetItemCollection.

     

    Look at the GetItem or TryGetItem methods. TryGetItem is safer, but GetItem is easier to type from the top of my head without intellisense helping Especially when using CSL  (C# as a second language). I'm definitely not worrying about a null value being thrown in this example.

     

    Code Snippet

    var myTypes= mdw.GetItem<EntityType)("insertmodelnamehere.Location",DataSpace.CSpace);

    var myprop=(from prop in myTypes where prop.Name=="Name" select prop).First

    //now drill in further to the TypeUsage property then you can find all of teh facets

    var facets=myprop.TypeUsage.Facets

    //iterate through the facets to find your maxlength

     

     

    The debugger is your friend here. THere's a lot of info in there.

     

    hth

    julie

    Wednesday, August 13, 2008 9:55 PM
  • Julie,

     

    I came up with a slightly different solution. I don't have to pass in the model name in addition to the context class name and entity name but run the risk of the context containing more than one name of typeName. I do wonder if there is a way to get at the csdl without firing up a copy of the context class? But realize that the xml could be in a number of different places (either resource or xml in the bin).

     

    So this is almost as funny as communicating via facebook....

     

    Thanks much for the help. You definately got me going in the right direction.

     

    -Andy

     

    Code Snippet

    private int GetFacetValue(string entityName, string typeName, string propertyName)

    {

    var context = (ObjectContext)Activator.CreateInstance(BuildManager.GetType(entityName, true));

    var csdl = context.MetadataWorkspace.GetItemCollection(DataSpace.CSpace);

    var entity = csdl.GetItems<EntityType>().Where(e => e.Name == typeName).SingleOrDefault();

    var property = entity.Properties.Where(p => p.Name == propertyName).SingleOrDefault();

    var facet = property.TypeUsage.Facets.Where(f => f.Name == "MaxLength").SingleOrDefault();

    }

     

     

     

     

    Wednesday, August 13, 2008 11:07 PM
  • If you don't have the context available you can still load the metadata without instantiating a context which in itself is an expensive operation.

     

    You can use file path references this way (copying and pasting from that chapter )

     

    Dim mdw = New MetadataWorkspace _

     (New String(){"C:\EFModels\BreakAwayModel.csdl", _

                   "C:\EFModels\BreakAwayModel.ssdl"}, _

      New Assembly(){})

     

    If they are embedded in an assembly then you can do this.

    Dim assem As Assembly = Assembly.LoadFile("C:\myapp\BreakAwayModel.dll")

    Dim mdw = New MetadataWorkspace _

        (New String() {"res://*/BreakAwayModel.csdl", _

                       "res://*/BreakAwayModel.ssdl"}, _

         New Assembly() {assem})

     

    This may be more expensive than instantiating a context. I haven't done any comparisons.

     

    Both of the examples assume I want multiple schemas loaded.

     

    You can also get the metadataworkspace from an entity connection. SO you can create an entityconnection (there are examples of this in the docs), then call it's metadataworkspace property.

     

    hth

    better than facebook because others get to benefit from it.

     

    julie

    Thursday, August 14, 2008 12:18 AM
  • Thanks,

     

    Maybe slightly off this thread topic but can an entity context (or is that object context) contain more than one model? Mainly asking whether I need to include the model name when searching an object context for a specific entity type.

     

    MyEntities : MyModel : Entity : Property

     

    or can I simply search on MyEntities : Entity : Property?

     

    Going after the context seems preferable to me as I don't have to worry aabout a connection string nore do I have to worry whether the schemas are resources or local xml files. Instantiating the context seems like a very very small performance hit to me in my case so I am not worried about that. I am caching the a subset of the MetadataWorkspace ItemsCollection and going back there on return hits which could be significant.

     

    Preordered that book of yours!

     

    -Andy

     

    Thursday, August 14, 2008 10:08 PM
  •  

    It's the ObjectContext.

     

    Only one model, but you still need to include the model name when you do the searching in the mdw for an entity or other type of metadata. (see Jarek's post below)

     

    By the way, once the metadata is loaded it stays in the application cache but you still need to access it using the context or the connection string.

     

    I don't know what you are doing exactly, but there really aren't any recommended practices around this stuff.

     

    I guess I'll have to come out to your user group again if you want me to sign the book. ;-)

    Friday, August 15, 2008 12:27 AM
  • Actually, you can have types from multiple schemas (namespaces) in a single workspace. Just put the types in separate CSDL files, load them together (either by specifying multiple csdl entries in Metadata= parameter in the connection string or by passing multiple csdl file paths to EdmItemCollection constructor). To reference type in a different namespace use fully qualified type name.

     

    A somewhat less obvious thing to remember is that while you declare <EntityContainer> within <Schema> it doesn't live in the namespace of the schema - containers don't have namespaces at all. You have to use unqualified "NorthwindEntities" instead of qualified "NorthwindModel.NorthwindEntities" which is not valid.

     

    Be aware, that there is a limitation of EFv1 which prevents you from using associations between types compiled as separate dlls. When you generate code from your CSDL files, make sure you compile them together in a single assembly, otherwise associations will not work. If you're only using EntityClient, this should work just fine, because there are no assemblies involved. Also when you only use associations between types compiled into the same assembly, things should be just fine.

    Friday, August 15, 2008 6:18 AM
  • Thanks Jarek.

     

    I think the RegisterItemCollection method confused me on this. After reading your explanation, then going back and re-reading the description of the method, I have a different understanding of it.

    Friday, August 15, 2008 11:01 AM
  • Ok, so it looks like there can be multiple models per context if I am reading this correctly.

     

    So, when searching a context for an entity, is it reasonable to allow a programmer to optionally qualify the search by providing (optional) a model name?

     

    context name, model name, entity name

     

    or

     

    context name, entity name

     

    Assuming this is all good, I will try to post my ultra secretive little project over on my blog over the weekend. Really not trying to be all that mysterious with all of this but rather give you the opportunity to get additional stars.

     

    Here is my EF (Property) Length expression builder for asp.net:

     

    http://blog.binaryocean.com/2008/08/15/TextBoxMaxLengthFromEntityFrameworkMetaData.aspx

     

    -Andy

     

    Friday, August 15, 2008 6:55 PM