Как стать автором
Обновить

Комментарии 16

items.Count()

Не затянули ли вы всю таблицу чтобы подсчитать количество записей?
Ну в общем то что заметил, разве что сложные отчеты это не к EF :).

Нет, там будет SELECT COUNT, я проверял (плохо). К тому же, это лишь пример.

EF нужен, чтобы универсально абстрагироваться от БД. Понятно, что разработчикам удобнее взять LinqPad, или просто написать запрос на SQL. А эту штуку можно сделать один раз, отдать пользователям, и забыть (но это не точно).
О нет! Вы правы, надо же к IQueryable привести. Поправил.
Визуализировать схему базы

Я вот активно использую EF, но для такого кейса точно бы выбрал native путь, через служебные таблицы конкретной СУБД, т.к. очевидно, стандартных средств EF для метаинформации может не хватить и все-равно придется лезть «глубже».
Это правда. Но как шпаргалка, когда нужно составить отчет, подойдёт, да и выглядит круто. На схеме буду не только таблицы, но и представления.
Спасибо за статью. Но к сожалению она устарела с выходом EFCore 5.0.
Так как в решении используются внутренние классы из EFCore, а в 5й версии разработчики много что изменили, особенно в части архитектуры, так что при миграции на 5ю версию EFCore пример работать не будет.
Здравствуйте! Нет, для перехода на NET 5 ничего, кроме версий пакетов в файле *.csproj менять не надо, всё работает без изменений (использую этот код в проекте на NET 5).
Да, вы правы. Прошу прощения. Я обновил через Nuget пакеты, и при стандартном импорте неправильно импортировалась Microsoft.EntityFrameworkCore.Design. Поэтому классы и интерфейсы были недоступны из этой библиотеки.
Однако варнинги немного внушают тревогу
Предупреждение EF1001 Microsoft.EntityFrameworkCore.Scaffolding.Internal.IScaffoldingModelFactory is an internal API that supports the Entity Framework Core infrastructure and not subject to the same compatibility standards as public APIs. It may be changed or removed without notice in any release.
Согласен, но в этом случае без internal API не обойтись. Практика показала, что этот API стабилен. Тем более, мы обходимся без Reflection для доступа к нему, а значит заметим, если он сломается при обновлении.
Статья мне очень помогла, я такой подход называю «Динамическая модель данных», может это не совсем корректно, но выражает суть лично для меня.
Одно мне не совсем очевидно, каким образом вы осуществляете доступ к конкретным значениям записей, или осуществляете выборку записей по условию в динамике. Не могли бы вы поделиться этим опытом, хотя бы вкратце. Спасибо.

И еще бы хотел добавить, что у реверс инженеринга, или подхода DatabaseFirst, как его можно назвать, есть тоже свои ограничения. Их не много, но они все же есть.
— not everything about the model is presented in the database schema. For example inheritance hierarchies, owned types and table splitting will not be reverse-engineered
— also, EF Core documentation claims, that there are some column types that will not be included in the model
— nullable types will not be mapped as nullable. For example, string columns that can be null, will not be scaffolded as string? type.
Я получаю список таблиц с помощью метода:
public IEnumerable<string> GetTableNames()
{
    DbContext context = contextFactory.CreateContext();
    return context.Model.GetEntityTypes.Select(e => e.Name);
}


Потом получаю информацию о полях нужной таблицы:
public TableInfo GetTableInfo(string entityName)
{
    var entityType = GetEntityType(entityName);

    var properties = entityType.GetProperties();
    var efProperties = entityType.GetServiceProperties();
    var allProperties = entityType.ClrType
        .GetProperties(BindingFlags.Public | BindingFlags.Instance)
        .Where(p => !efProperties.Any(ep => ep.Name == p.Name));

    return new TableInfo
    {
        EntityType = entityType,
        Properties = properties,
        AllProperties = allProperties,
        NavProperties = allProperties.Where(p => !properties.Any(ep => ep.Name == p.Name))
    };
}


public class TableInfo
{
    public IEntityType EntityType { get; set; }
    public IEnumerable<PropertyInfo> AllProperties { get; set; }
    public IEnumerable<PropertyInfo> NavProperties { get; set; }
    public IEnumerable<IProperty> Properties { get; set; }
}


Потом генерирую код запроса в виде строки, компилирую и выполняю его динамически с помощью Roslyn. В статье под спойлером «Пример» есть картинки того, как это у меня выглядит.

Для упрощения работы с результатами запроса использую Z.EntityFramework.Plus.EFCore.
Большое спасибо за развернутый ответ.
Потом генерирую код запроса в виде строки, компилирую и выполняю его динамически с помощью Roslyn.

Вот про этот момент и спрашивал. Я сначала пробовал через .NET Reflection получить доступ к значениям. Но если ты начал работать с Reflection тот так и должен обращаться в дальнейшем.
Т.е. по факту, вы стоите на C# выражение LinqToSql, затем компилируете его с помощью Roslin, а затем выполняете в runtime скомпилированный ранее вами код, я правильно понял ваш ответ?

Для упрощения работы с результатами запроса использую Z.EntityFramework.Plus.EFCore.

Да, очень полезная библиотека, тоже ее использую. У ее автора еще очень полезный блог по Entity Framework erikej.github.io
Да, вы поняли правильно.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории