9

I've created an EDMX object from a database I'm programming against.

I need to get input from a user and save it to a row in the database table. The problem is that I need to limit the length of input strings to the width of the corresponding VARCHAR column in the database.

When I browse the model, I can clearly see in the properties window that the model knows the max length of the string, but I don't know how to access this data in code.

If I want to write something like this:

Entities entities = new Entities();
myTable = entities.myTable.First();
if (userInput.length > myTable.columnA.MaxLength)
{
    // tell the user that the input is too long.
}
else
{
    myTable.columnA = userInput;
}

How do I write it?

Update: I would like to point out that the IObjectContextAdapater mentioned in the answers below is in the System.Data.Entity.Infrastructure namespace.

Vivian River
  • 31,198
  • 62
  • 198
  • 313
  • I'm surprised by the low number of views on this question. Thanks very much for the helpful answers; I might have never figured it out on my own. – Vivian River Nov 20 '14 at 20:35
  • If you run into a situation where you need to bring `MaxLength` value of a table column *directly from the Database*, here's a good answer: https://stackoverflow.com/a/71330103/8644294 – Ash K Mar 03 '22 at 16:27

3 Answers3

17

Here are two methods by which you can read the meta data:

int? GetMaxLength(DbContext context, string tableName, string propertyName)
{
    var oc = ((IObjectContextAdapter)context).ObjectContext;

    return oc.MetadataWorkspace.GetItems(DataSpace.CSpace).OfType<EntityType>()
             .Where(et => et.Name == tableName)
             .SelectMany(et => et.Properties.Where(p => p.Name == propertyName))
             .Select (p => p.MaxLength)
             .FirstOrDefault();
}

int? GetMaxLength<T>(DbContext context, Expression<Func<T, object>> property)
{
    var memberExpression = (MemberExpression)property.Body;
    string propertyName = memberExpression.Member.Name;
    return GetMaxLength(context, typeof(T).Name, propertyName);
}

So you can either enter the table name and property name, or an expression that specifies the property you're interested in.

Another approach could be to create a MetaData class and use the MaxLength attribute.

Gert Arnold
  • 105,341
  • 31
  • 202
  • 291
  • I'm confused. I thought that the EDMX entities is an ObjectContext, which has nothing to do with DbContext. – Vivian River Nov 19 '14 at 22:19
  • 1
    Not necessarily. You'd have to check. If it is an `ObjectContext` you don't need this `((IObjectContextAdapter)context).ObjectContext` part. – Gert Arnold Nov 19 '14 at 22:21
  • I did check and I see that it's a DbContext. To be honest, I have heard of DbContext, but I haven't read up on all the new features of the new Entity Framework versions, so this one got past me. Wow, there is so much keeping up to do in the .net world! – Vivian River Nov 19 '14 at 22:24
  • The function `GetItems` returns an enumeration of 393 items. However, the `OfType` function, where myTable is a model of a SQL table, returns an empty enumeration. – Vivian River Nov 19 '14 at 22:56
  • 2
    You should leave `EntityType` there, it's an EF class. – Gert Arnold Nov 19 '14 at 23:05
  • Oops, I thought it was a placeholder for my entity type. – Vivian River Nov 19 '14 at 23:18
  • You might want to add "using System.Data.Entity.Core.Metadata.Edm;" and "using System.Data.Entity.Infrastructure;" – Joe Maffei Mar 23 '20 at 16:13
  • First example:I am using EF 6.4.4 Nuget package in a .Net Framework 4.8 project. My EF context does not cast to an IObjectContextAdapter object: Unable to cast... to ... error. Second example: I cannot use as there is no indication of what is passed as "property." – pwrgreg007 Apr 14 '21 at 18:57
  • 1
    @pwrgreg007 Feel free to post a question in which you have ample opportunity to explain your problem. A comment is not a the best way to ask new questions. – Gert Arnold Apr 14 '21 at 19:01
2

It's not very pretty; reading edmx properties at runtime is not something Microsoft exposed easily or documented well (or in some cases, at all). context is your DBContext.

var objectContext = ((IObjectContextAdapter)context).ObjectContext;
var entityType = objectContext.MetadataWorkspace.GetItems<EntityType>(DataSpace.CSpace).Where(e => e.Name == "your entity name").First();
var facets = entityType.Properties["your property name"].TypeUsage.Facets;

facets will look something like this, so you'll need to look for the MaxLength Name(may not exist, depending on the underlying field type) and get the Value:

Count = 5
    [0]: Nullable=false
    [1]: DefaultValue=null
    [2]: MaxLength=250
    [3]: Unicode=false
    [4]: FixedLength=false
Paul Abbott
  • 7,065
  • 3
  • 27
  • 45
  • Is context the instantiation of the entities from the EDMX, or are you talking about something else? – Vivian River Nov 19 '14 at 19:19
  • I'm getting an error with your code. When I write code like your example, I use a class imported from a SQL table for `EntityType` and I get an error: The type cannot be used as type parameter 'T'... there is no implicit reference conversion from `myTable` to `GlobalItem`. What does this mean? – Vivian River Nov 19 '14 at 22:08
  • 1
    Leave GetItems be, the only thing you need to replace are the two strings. – Paul Abbott Nov 20 '14 at 00:01
  • I am using EF 6.4.4 Nuget package in a .Net Framework 4.8 project. My EF context does not cast to an IObjectContextAdapter object: Unable to cast... to ... error. – pwrgreg007 Apr 14 '21 at 18:58
1

If you modify the T4 template you can add your own attribute to the properties that have MaxLength set.

If you can find the right place to add it, it's something as simple as this:

var lengthAttributeText = edmProperty.MaxLength.HasValue
   ? string.Format("[MaxLength({0})] ", edmProperty.MaxLength.Value)
   : "";

And then add this into the text for the property line. (Tricky to be more detailed since I've already modified my .tt file a lot; also the lack of proper IDE support for .tt files makes this a lot harder than it could be.)

Dave Cousineau
  • 12,154
  • 8
  • 64
  • 80