Getting Database column length with LINQ to Entities

During the work with ADO.Net Entity Framework sometimes you need to know a metadata for a database you’re working with such as a nchar/nvarchar column max length. Trying to update a DB column using LINQ to Entities with a string greater than the column max length leads to an SqlException (e.g. System.Data.SqlClient.SqlException: String or binary data would be truncated); therefore you need to check that your data does not exceed DB column boundaries manually. LINQ won't do this for you on a run-time.

If you don't want to have all your Entity Model metadata hardcoded, you need to get it on a run-time. Here is described how you can do this with LINQ to SQL.

Unfortunately this approach seems not to work for Entities Model. In order to do this for Entities you would need to query MetadataWorkSpace class and get a conceptual (CSpace) metadata for your Entity:

public static int GetMaxLength(Type entityType, string columnName)
{
    int result = 0;

    using (myEntities context = new myEntities())
    {
        var queryResult = from meta in context.MetadataWorkspace.GetItems(DataSpace.CSpace)    //getting conceptual entity metadata
                          where meta.BuiltInTypeKind == BuiltInTypeKind.EntityType
                                && (meta as EntityType).Name == entityType.Name    //selecting desired entity by name
                          from property in (meta as EntityType).Properties
                          where property.Name == columnName    //selecting an entity property that matches the column name
                                && (property.TypeUsage.EdmType.Name == "String")            
                          select property.TypeUsage.Facets["MaxLength"].Value;              

        if (queryResult.Count() > 0)
        {
            result = Convert.ToInt32(queryResult.First());
        }
    }
    return result;
}

When you call this method, just pass a type of your entity e.g.

GetMaxLength(typeof(myEntity), "myColumnName");

2 comments:

Guille said...

Hi, thank you for your code. This is how I translated it to VB.Net, as a function added to my context object (I hope it pastes OK in the comment form):

Public Function Length(Of TEntity As EntityObject)(field As String) As Integer

Dim typename As String = GetType(TEntity).Name
Dim qres = From meta In MetadataWorkspace.GetItems(DataSpace.CSpace) _
Where meta.BuiltInTypeKind = BuiltInTypeKind.EntityType _
AndAlso CType(meta, EntityType).Name = typename _
From prop In CType(meta, EntityType).Properties _
Where prop.Name = field AndAlso prop.TypeUsage.EdmType.Name = "String" _
Select prop.TypeUsage.Facets("MaxLength").Value

If qres.Count = 0 Then Throw New Exception("Invalid use of Context.Length(Of " & typename & ")(""" & field & """)")

Return CInt(qres.First())

End Function

Best regards!

Anonymous said...

AWESOME