Исключить свойство модели из загрузки в MVC5 EF6 [duplicate]

Я не думаю, что вы можете программно настроить класс R, поскольку он автоматически создается ADT.

39
задан Mark Kram 23 January 2012 в 20:51
поделиться

7 ответов

Есть ли способ получить список, но без заполнения этого столбца?

Не без проекции, которую вы хотите избежать. Если столбец отображается, он является естественной частью вашего объекта. Объект без этого столбца не является полным - это другой набор данных = проекция.

Я использую здесь анонимный тип, потому что иначе вы получите исключение NotSupportedException: объект или сложный тип «ProjectName.File» не может быть сконструирован в запросе LINQ to Entities.

Как исключение говорит, что вы не можете проецировать отображаемый объект. Я упомянул выше: проекция делает разные данные и EF не нравится «частичные сущности».

Ошибка 16 Ошибка 3023: проблема с отображением фрагментов, начиная с строки 2717: Файлы столбцов. Данные в таблице Файлы должны быть сопоставлены: он не имеет значения по умолчанию и не имеет значения NULL.

< / blockquote>

Недостаточно удалить свойство из конструктора. Вы должны открыть EDMX как XML и удалить столбец из SSDL, что сделает вашу модель очень хрупкой (каждое обновление из базы данных вернет ваш столбец). Если вы не хотите отображать столбец, вы должны использовать представление базы данных без столбца и сопоставить представление вместо таблицы, но вы не сможете вставлять данные.

Как обходной путь для всех ваших проблем используйте расщепление таблицы и разделите проблемный двоичный столбец на другой объект с соотношением 1: 1 к вашему основному объекту File.

14
ответ дан Ladislav Mrnka 26 August 2018 в 16:18
поделиться

Я хотел бы поделиться своими попытками решить эту проблему, если кто-то другой находится в той же ситуации.

Я начал с того, что предложил Джереми Данью , который мне является менее болезненным вариантом.

// You need to include all fields in the query, just make null the ones you don't want.
var results = context.Database.SqlQuery<myEntity>("SELECT Field1, Field2, Field3, HugeField4 = NULL, Field5 FROM TableName");

В моем случае мне понадобился объект результата IQueryable<>, поэтому я добавил AsQueryable() в конце. Это, конечно, позволяет мне добавлять вызовы к .Where, .Take и другим командам, которые все мы знаем, и они отлично работали. Но есть оговорка:

Обычный код (в основном context.myEntity.AsQueryable()) возвратил System.Data.Entity.DbSet<Data.DataModel.myEntity>, а этот подход вернулся System.Linq.EnumerableQuery<Data.DataModel.myEntity>.

По-видимому, это означает, что мой пользовательский запрос получает исполняемый «как есть», как только это необходимо, и фильтрация, которую я добавил позже, выполняется впоследствии, а не в базе данных.

Поэтому я попытался имитировать объект Entity Framework, используя точный запрос EF, созданный, даже с теми [Extent1], но это не сработало. При анализе результирующего объекта его запрос заканчивается как

FROM [dbo].[TableName] AS [Extent1].Where(c => ...

вместо ожидаемого

FROM [dbo].[TableName] AS [Extent1] WHERE ([Extent1]...

В любом случае, это работает, и пока таблица не огромна, этот метод будет достаточно быстрым. В противном случае у вас нет возможности, кроме как вручную добавлять условия, объединяя строки, например, классический динамический SQL. Очень простой пример, если вы не знаете, о чем я говорю:

string query = "SELECT Field1, Field2, Field3, HugeField4 = NULL, Field5 FROM TableName";
if (parameterId.HasValue)
    query += " WHERE Field1 = " + parameterId.Value.ToString();
var results = context.Database.SqlQuery<myEntity>(query);

Если вашему методу иногда требуется это поле, вы можете добавить параметр bool, а затем сделать что-то вроде это:

IQueryable<myEntity> results;
if (excludeBigData)
    results = context.Database.SqlQuery<myEntity>("SELECT Field1, Field2, Field3, HugeField4 = NULL, Field5 FROM TableName").AsQueryable();
else
    results = context.myEntity.AsQueryable();

Если кому-то удастся заставить расширения Linq работать правильно, как если бы это был оригинальный объект EF, прокомментируйте, чтобы я мог обновить ответ.

0
ответ дан Community 26 August 2018 в 16:18
поделиться

вы можете сделать это:

var files = dbContext.Database.SqlQuery<File>("select FileId, DataType, MimeType from Files");

или это:

var files = objectContext.ExecuteStoreQuery<File>("select FileId, DataType, MimeType from Files");

в зависимости от вашей версии EF

6
ответ дан Jeremy Danyow 26 August 2018 в 16:18
поделиться

Я пробовал это:

Из диаграммы edmx (EF 6) я нажал на столбец, который я хотел скрыть от EF, и по их свойствам вы можете установить свой getter и setter в закрытый. Таким образом, для меня это работает.

Я возвращаю некоторые данные, которые содержат ссылку на пользователя, поэтому я хотел скрыть поле «Пароль», даже если он зашифрован и солен, я просто не хотел его на моем json , и я не хотел делать:

Select(col => new {}) 

, потому что это боль для создания и поддержки, особенно для больших таблиц с большим количеством отношений.

Недостаток этот метод заключается в том, что если вы когда-либо обновляете свою модель, вам нужно будет снова изменить их приемник и сеттер.

0
ответ дан mikesoft 26 August 2018 в 16:18
поделиться

У меня было это требование, потому что у меня есть объект Document, у которого есть поле Content с содержимым файла, то есть размером около 100 МБ, и у меня есть функция поиска, которую я хотел бы вернуть остальную часть столбцы.

Я решил использовать проецирование:

IQueryable<Document> results = dbContext.Documents.Include(o => o.UploadedBy).Select(o => new {
    Content = (string)null,
    ContentType = o.ContentType,
    DocumentTypeId = o.DocumentTypeId,
    FileName = o.FileName,
    Id = o.Id,
    // etc. even with related entities here like:
    UploadedBy = o.UploadedBy
});

Затем мой контроллер WebApi передает этот объект results в общую функцию Pagination, которая применяет .Skip, .Take и .ToList.

Это означает, что когда запрос выполняется, он не обращается к столбцу Content, поэтому данные 100 МБ не затрагиваются, и запрос выполняется так же быстро, как вы хотите / ожидаете, что это будет.

Затем я вернул его в мой класс DTO, который в этом случае почти точно такой же, как класс сущности, поэтому это может быть не шаг вам нужно реализовать, но это соответствует моему типичному шаблону кодирования WebApi, поэтому:

var dtos = paginated.Select(o => new DocumentDTO
{
    Content = o.Content,
    ContentType = o.ContentType,
    DocumentTypeId = o.DocumentTypeId,
    FileName = o.FileName,
    Id = o.Id,
    UploadedBy = o.UploadedBy == null ? null : ModelFactory.Create(o.UploadedBy)
});

Затем я возвращаю список DTO:

return Ok(dtos);

. Поэтому он использует проекцию, которая может не соответствуют требованиям оригинального плаката, но если вы используете классы DTO, вы все равно конвертируете. Вы можете так же легко сделать следующее, чтобы вернуть их в качестве ваших реальных объектов:

var dtos = paginated.Select(o => new Document
{
    Content = o.Content,
    ContentType = o.ContentType,
    DocumentTypeId = o.DocumentTypeId,
    //...

Всего несколько дополнительных шагов, но это работает для меня хорошо.

2
ответ дан Sean 26 August 2018 в 16:18
поделиться

Я использую здесь анонимный тип, потому что иначе вы получите исключение NotSupportedException: объект или сложный тип «ProjectName.File» не может быть сконструирован в запросе LINQ to Entities.

var file = context.Files
        .Where(f => f.Id == idFile)
        .FirstOrDefault() // You need to exeucte the query if you want to reuse the type
        .Select(f => new {
            f.Id, f.MimeType, f.Size, f.FileName, f.DataType,
            f.DateModification, f.FileId
        }).FirstOrDefault();

А также неплохая практика де-нормализации таблицы в дальнейшем, то есть одна с метаданными и одна с полезной нагрузкой, чтобы избежать проецирования. Проецирование будет работать, единственная проблема - отредактировать любое время, когда новый столбец будет добавлен в таблицу.

1
ответ дан skjagini 26 August 2018 в 16:18
поделиться

Я бы сделал что-то вроде этого:

var result = from thing in dbContext.Things
             select new Thing {
                 PropertyA = thing.PropertyA,
                 Another = thing.Another
                 // and so on, skipping the VarBinary(MAX) property
             };

Где Thing - ваша организация, которую EF знает, как материализоваться. Результирующий оператор SQL не должен содержать большой столбец в его результирующем наборе, поскольку он не нужен в запросе.

EDIT: из ваших правков вы получаете ошибку NotSupportedException: сущность или комплекс тип «ProjectName.File» не может быть сконструирован в запросе LINQ to Entities. , потому что вы не сопоставили этот класс как сущность. Вы не можете включать объекты в запросы LINQ to Entities, которые EF не знает, и ожидать, что они сгенерируют соответствующие операторы SQL.

Вы можете сопоставить другой тип, который исключает столбец VarBinary(MAX) в его определении или используйте приведенный выше код.

9
ответ дан Yuck 26 August 2018 в 16:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: