рамка на обект 5 MaxLength

Използвах 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?


person Eonasdan    schedule 11.09.2012    source източник
comment
Имах всякакви проблеми с EF5, свързани с препратките към асемби. Опитахте ли да деинсталирате и инсталирате EF5 отново с помощта на конзолата за управление на пакети? Това реши някои от проблемите ми по-рано. Не забравяйте да направите това за всички ваши проекти в решението. Може би си струва да опитате.   -  person Automatico    schedule 12.09.2012
comment
това е нова инсталация на VS2012 и нов проект. Внасям код от по-стар проект   -  person Eonasdan    schedule 12.09.2012


Отговори (4)


Това означава, че не само сте надстроили EF, но сте променили и API. Има два API - основният API на ObjectContext и опростен API на DbContext. Вашият код зависи от ObjectContext API (единственият API, наличен в EF4), но EF5 използва DbContext API (добавен в отделно сглобяване на EntityFramework.dll от EF4.1). Ако искате да използвате нови функции на EF и предишния си код, трябва просто да надстроите до .NET 4.5.

Ако също искате да използвате нов API, ще трябва да актуализирате голяма част от съществуващия си код, но все още е възможно да получите ObjectContext от DbContext и методът ви да работи отново. Просто трябва да използвате този фрагмент:

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

и използвайте objectContext вместо context във вашия код.

person Ladislav Mrnka    schedule 12.09.2012
comment
Да, трябваше да направя това по-ясно. Създадох нов проект за надграждане до новата горещина. Направих промяната, но получавам грешката „Project.Model.fooEntities е „тип“, но се използва като „променлива“ - person Eonasdan; 12.09.2012
comment
Съжалявам, моя е грешката. Неправилно съм написал примера. Проверете коригираната версия. - person Ladislav Mrnka; 12.09.2012
comment
това реши тази грешка, но сега получавам несвързана грешка. въздишка :) благодаря - person Eonasdan; 12.09.2012

Това е много удобен код. Преработих го малко и е толкова полезно, че реших да го публикувам тук.

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);

Това предполага, че имате DbSet, дефиниран във вашия DbContext от тип Customer, който има свойство CustomerName с дефинирана MaxLength.

Това е много полезно за неща като създаване на атрибути на модела, които задават максималната дължина на текстовото поле на максималната дължина на полето в базата данни, като винаги се гарантира, че двете са еднакви.

person mccow002    schedule 18.10.2012
comment
Какво е EFContext? Ако това е вашето приложение. специфичен генериран клас, трябва да го подадете като параметър, а не да го правите вграден в статична функция - вижте IOC. - person Michael Freidgeim; 30.06.2013
comment
Пич u rock u, току-що прекарах един час в това и не можах да разбера как да го стартирам. Вашите кодове работят почти директно, просто не забравяйте да проверите контекста си, това е страхотно - person Termiux; 29.07.2013
comment
Работи перфектно! Промених го, за да хвърля изключение, вместо да връща нула. - person Jowen; 31.10.2013
comment
Трябваше да включа: System.Linq, System.Linq.Expressions, System.Data.Entity.Infrastructure и System.Data.Metadata.Edm. Добавих това към контролера на абстрактния предшественик в моето приложение MVC и върши работата добре. - person Mark Micallef; 27.02.2014
comment
Също така го направих да хвърля изключение вместо да връща null и вместо да извикам EfContext(), вместо това предавам DbContext от извикващия. Подписът на метода изглежда така: защитен статичен int GetMaxColumnLength‹T›(DbContext db, Expression‹Func‹T, string›› колона) - person Mark Micallef; 27.02.2014

Преработих примера на 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;

    }

}
person Walter Stabosz    schedule 04.04.2014
comment
.Select(sel => sel) в долната част не прави нищо, нали? Извадих го и изглежда не ми пука. - person David; 28.08.2018
comment
Вие сте прав, в този случай, не, Select не прави нищо. Но това е само защото ламбда изразът връща свой собствен входен параметър. Ако беше нещо като .Select(sel => sel.SomeProperty), тогава изтриването на Select щеше да върне различно result. - person Walter Stabosz; 28.08.2018

Имах подобен проблем и решението е тук;

  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                          
                   };
person Muru Bakthavachalam    schedule 08.03.2014