【问题标题】:entity framework 5 MaxLength实体框架 5 MaxLength
【发布时间】:2014-04-05 04:44:33
【问题描述】:

我正在使用 EF4 和我发现的一段代码从这样的实体中获取 MaxLength 值:

public static int? GetMaxLength(string entityTypeName, string columnName)
        {
            int? result = null;
            using (fooEntities context = new fooEntities())
            {
                Type entType = Type.GetType(entityTypeName);
                var q = from meta in context.MetadataWorkspace.GetItems(DataSpace.CSpace)
                                  .Where(m => m.BuiltInTypeKind == BuiltInTypeKind.EntityType)
                        from p in (meta as EntityType).Properties
                        .Where(p => p.Name == columnName
                                    && p.TypeUsage.EdmType.Name == "String")
                        select p;

                var queryResult = q.Where(p =>
                {
                    bool match = p.DeclaringType.Name == entityTypeName;
                    if (!match && entType != null)
                    {
                        match = entType.Name == p.DeclaringType.Name;
                    }

                    return match;

                }).Select(sel => sel.TypeUsage.Facets["MaxLength"].Value);
                if (queryResult.Any())
                {
                    result = Convert.ToInt32(queryResult.First());
                }

                return result;
            }
        }

但是,我升级到 EF5 并且我知道收到此错误消息:

...fooEntities'  does not contain a definition for 'MetadataWorkspace' and no
extension method 'MetadataWorkspace' accepting a first argument of type
'...fooEntities' could be found (are you missing a using directive or an assembly
 reference?)

从 EF5 获取元数据的最佳方式是什么?

【问题讨论】:

  • 我遇到了与 EF5 相关的程序集引用的各种问题。您是否尝试过使用包管理器控制台再次卸载和安装 EF5?这解决了我之前的一些问题。确保对解决方案中的所有项目执行此操作。可能值得一试。
  • 这是一个全新安装的 VS2012 和一个全新的项目。我从旧项目中引入代码
  • 注意:它不会带来来自数据库列的MaxLength值。如果您没有在模型属性中注释长度,例如:[Column("SomeColumn", TypeName="varchar(10)")],则此代码仅返回 Max for property.TypeUsage.Facets["MaxLength"].Value,这会使其遇到 Cast 异常。如果您想要长度,即 10 在这种情况下直接来自数据库,请在此处查看我的答案:stackoverflow.com/a/71330103/8644294

标签: c# asp.net-mvc-4 entity-framework-5


【解决方案1】:

这是一段非常方便的代码。我对其进行了一些重构,它非常有用,我想我会在这里发布。

public static int? GetMaxLength<T>(Expression<Func<T, string>> column)
    {
        int? result = null;
        using (var context = new EfContext())
        {
            var entType = typeof(T);
            var columnName = ((MemberExpression) column.Body).Member.Name;

            var objectContext = ((IObjectContextAdapter) context).ObjectContext;
            var test = objectContext.MetadataWorkspace.GetItems(DataSpace.CSpace);

            if(test == null)
                return null;

            var q = test
                .Where(m => m.BuiltInTypeKind == BuiltInTypeKind.EntityType)
                .SelectMany(meta => ((EntityType) meta).Properties
                .Where(p => p.Name == columnName && p.TypeUsage.EdmType.Name == "String"));

            var queryResult = q.Where(p =>
                                          {
                                              var match = p.DeclaringType.Name == entType.Name;
                                              if (!match)
                                                  match = entType.Name == p.DeclaringType.Name;

                                              return match;

                                          })
                .Select(sel => sel.TypeUsage.Facets["MaxLength"].Value)
                .ToList();

            if (queryResult.Any())
                result = Convert.ToInt32(queryResult.First());

            return result;
        }
    }

你可以这样称呼它:

GetMaxLength<Customer>(x => x.CustomerName);

这是假设您已在 Customer 类型的 DbContext 中定义了一个 DbSet,该 DbSet 具有 CustomerName 属性和定义的 MaxLength。

这对于创建模型属性(将文本框的最大长度设置为数据库中字段的最大长度)非常有用,始终确保两者相同。

【讨论】:

  • 什么是 EFContext?如果它是你的应用程序。具体生成的类,你应该把它作为参数传递,而不是让它嵌入到静态函数中——见IOC。
  • 老兄,你太棒了,我只花了一个小时,不知道如何运行它。您的代码几乎可以直接运行,只需记住检查您的上下文,这太棒了
  • 完美运行!我将其更改为抛出异常而不是返回 null。
  • 我必须包括:System.Linq、System.Linq.Expressions、System.Data.Entity.Infrastructure 和 System.Data.Metadata.Edm。将此添加到我的 MVC 应用程序中的抽象祖先控制器中,它很好地完成了这项工作。
  • 还让它抛出异常而不是返回 null,而不是调用 EfContext() 我而是从调用者传入 DbContext。方法签名如下所示:protected static int GetMaxColumnLength(DbContext db, Expression> column)
【解决方案2】:

我将 mccow002 的示例重构为一个可复制粘贴的扩展方法类:

using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Metadata.Edm;

public static class DbContextExtensions
{

    // get MaxLength as an extension method to the DbContext
    public static int? GetMaxLength<T>(this DbContext context, Expression<Func<T, string>> column)
    {
        return (int?)context.GetFacets<T>(column)["MaxLength"].Value;
    }

    // get MaxLength as an extension method to the Facets (I think the extension belongs here)
    public static int? GetMaxLength(this ReadOnlyMetadataCollection<Facet> facets)
    {
        return (int?)facets["MaxLength"].Value;            
    }

    // just for fun: get all the facet values as a Dictionary 
    public static Dictionary<string,object> AsDictionary(this ReadOnlyMetadataCollection<Facet> facets) {
        return facets.ToDictionary(o=>o.Name,o=>o.Value);
    }


    public static ReadOnlyMetadataCollection<Facet> GetFacets<T>(this DbContext context, Expression<Func<T, string>> column)
    {
        ReadOnlyMetadataCollection<Facet> result = null;

        var entType = typeof(T);
        var columnName = ((MemberExpression)column.Body).Member.Name;

        var objectContext = ((IObjectContextAdapter)context).ObjectContext;
        var test = objectContext.MetadataWorkspace.GetItems(DataSpace.CSpace);

        if (test == null)
            return null;

        var q = test
            .Where(m => m.BuiltInTypeKind == BuiltInTypeKind.EntityType)
            .SelectMany(meta => ((EntityType)meta).Properties
            .Where(p => p.Name == columnName && p.TypeUsage.EdmType.Name == "String"));

        var queryResult = q.Where(p =>
        {
            var match = p.DeclaringType.Name == entType.Name;
            if (!match)
                match = entType.Name == p.DeclaringType.Name;

            return match;

        })
            .Select(sel => sel)
            .FirstOrDefault();

        result = queryResult.TypeUsage.Facets;

        return result;

    }

}

【讨论】:

  • 底部的.Select(sel =&gt; sel) 没有任何作用,是吗?我把它拿出来,它似乎不在乎。
  • 你是对的,在这种情况下,Select 不做任何事情。但这只是因为 lambda 表达式正在返回它自己的输入参数。如果它是 .Select(sel =&gt; sel.SomeProperty) 之类的东西,那么删除 Select 会返回一个不同的 result
【解决方案3】:

这意味着您不仅升级了 EF,还更改了 API。有两个 API - 核心 ObjectContext API 和简化的 DbContext API。您的代码依赖于 ObjectContext API(EF4 中唯一可用的 API),但 EF5 使用 DbContext API(自 EF4.1 起在单独的 EntityFramework.dll 程序集中添加)。如果您想使用新的 EF 功能和以前的代码,您应该升级到 .NET 4.5。

如果您还想使用新的 API,您将不得不更新大量现有代码,但仍然可以从 DbContext 获取 ObjectContext 并使您的方法再次工作。你只需要使用这个sn-p:

var objectContext = ((IObjectContextAdapter)context).ObjectContext;

并在您的代码中使用objectContext 而不是context

【讨论】:

  • 是的,我应该更清楚地说明这一点。我创建了一个新项目来升级到“新热点”。我进行了更改,但出现错误“Project.Model.fooEntities is a 'type' but is used like a 'variable'
  • 对不起,我的错。我错误地写了这个例子。检查更正后的版本。
  • 这解决了 that 错误,但现在我遇到了一个不相关的错误。 叹息 :) 谢谢
【解决方案4】:

我有类似的问题,解决方案在这里;

  MyDBEntities ctx = new MyDBEntities();
        var objectContext = ((IObjectContextAdapter)ctx).ObjectContext;

        var cols = from meta in objectContext.MetadataWorkspace.GetItems(DataSpace.CSpace)
                   .Where(m => m.BuiltInTypeKind == BuiltInTypeKind.EntityType)
                   from p in (meta as EntityType).Properties
                      .Where(p => p.DeclaringType.Name == "TableName")
                   select new
                   {
                       PropertyName = p.Name                          
                   };

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多