2016-08-24 2 views
1

Я пытаюсь проверить, имеет ли сущность в базе данных какие-либо отношения внешних ключей, чтобы я мог сообщить пользователю, что объект может или не может быть удален.Запросить запрос на анонимный словарь <string,int>

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

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

private bool CanDeleteComponent(int compId) 
{ 
    var query = _Context.Components.Where(c => c.ComponentID == compId) 
     .Select(comp => new 
     { 
      References = comp.Incidents.Any() && 
      comp.Drawings.Any() && 
      comp.Documents.Any() && 
      comp.Tasks.Any() && 
      comp.Images.Any() && 
      comp.Instructions.Any() 
     }); 
    var result = query.FirstOrDefault(); 
    if (result != null) 
    { 
     return !result.References; 
    } 
    return true; 
} 

Это выполняет ряд SELECT COUNT(*) FROM <TABLE> WHERE... запросов.

Теперь я хотел бы предоставить дополнительную информацию о количестве ссылок. В идеале я хотел бы вернуть словарь с указанным именем данных и связанным счетчиком. Таким образом, я могу перебирать результат, а не обращаться к отдельным свойствам анонимного типа. Тем не менее, то, что я пытался результаты в виде исключения:

var query = _Context.Components.Where(c => c.ComponentID == compId) 
     .Select(comp => new Dictionary<string, int> 
     { 
      {"Events", comp.Incidents.Count()}, 
      {"Drawings", comp.Drawings.Count()}, 
      {"Documents", comp.Documents.Count()}, 
      {"Tasks", comp.Tasks.Count()}, 
      {"Images", comp.Images.Count()}, 
      {"Instructions", comp.Instructions.Count()}, 
     }); 
    var result = query.FirstOrDefault(); 
    return query.Any(fk => fk.Value > 0); 

Исключения, которое возникает в:

A first chance exception of type 'System.NotSupportedException' occurred in EntityFramework.SqlServer.dll 
Additional information: Only list initializer items with a single element are supported in LINQ to Entities. 

Есть ли способ обойти это, так что я могу вернуть какие-то IEnumerable, а не анонимный тип?

Благодаря

EDIT В настоящее время я ленивая загрузка отключена в моем контексте. Если есть решение без поворота на ленивую загрузку, это будет оценено по достоинству.

ответ

3

Вы не можете построить Dictionary<K,V> в заявлении SELECT, поэтому вы получаете System.NotSupportedException. Сначала вы можете получить одиночный Component по запросу и построить словарь в памяти.

var comp = _Context.Components.SingleOrDefault(c => c.ComponentID == compId); 
var dict = new Dictionary<string, int>() 
{ 
    { "Events", comp.Incidents.Count()}, 
    { "Drawings", comp.Drawings.Count()}, 
    { "Documents", comp.Documents.Count()}, 
    { "Tasks", comp.Tasks.Count()}, 
    { "Images", comp.Images.Count()}, 
    { "Instructions", comp.Instructions.Count()} 
}; 

EDIT Если вы не используете отложенной загрузки, вы можете явно .Include свойства в запросе:

var comp = _Context.Components 
    .Include(c => c.Incidents) 
    ... 
    .SingleOrDefault(c => c.ComponentID == compId); 
+0

Спасибо, я вижу, что это сработает, если у меня LazyLoadingEnabled = true. Есть ли способ отключить его? – Simon

+0

@Simon См. Мое редактирование. –

+0

спасибо, но теперь это загружает все навигационные данные, которые могут быть довольно большими и интенсивными в памяти, что я и стараюсь избежать. Конечной целью является выполнение только запросов 'SELECT COUNT()' для каждой таблицы FK. – Simon

0

Есть ли способ обойти это, так что я могу вернуть часть вроде IEnumerable, а не анонимного типа?

На самом деле есть, хотя я не уверен, что вам понравится сгенерированный SQL (по сравнению с тем, который использует анонимный тип).

var query = _Context.Components.Where(c => c.ComponentID == compId) 
    .SelectMany(comp => new [] 
    { 
     new { Key = "Events", Value = comp.Incidents.Count() }, 
     new { Key = "Drawings", Value = comp.Drawings.Count() }, 
     new { Key = "Documents", Value = comp.Documents.Count() }, 
     new { Key = "Tasks", Value = comp.Tasks.Count() }, 
     new { Key = "Images", Value = comp.Images.Count() }, 
     new { Key = "Instructions", Value = comp.Instructions.Count() }, 
    }.ToList()); 

var result = query.ToDictionary(e => e.Key, e => e.Value); 

return query.Any(fk => fk.Value > 0); 
+0

Я не могу заставить это работать. Для начала пример не компилируется для меня, пока я не ставил 'new' перед каждым анонимным объектом. Во-вторых, я получаю сообщение об ошибке «Тип массива» <> f__AnonymousType1'2 [System.String, System.Int32] [] 'не может быть инициализирован в результате запроса. Вместо этого используйте «System.Collections.Generic.List'1 [<> f__AnonymousType1'2 [System.String, System.Int32]]». – erdomke

+0

@erdomke. Вы правы в 'new' перед каждым элементом массива. Что касается исключения, которое вы получаете, это происходит, если вы используете 'Select' вместо' SelectMany'. Добавление 'ToList()' в конце делает его работу как в 'Select', так и' SelectMany' - см. Обновление. EF - странный монстр :) –

+0

Вы правы, что мне удалось замаскировать ваше использование SelectMany. Пример теперь работает для меня, но только если я опускаю недавно добавленный ToList(). С помощью ToList я получаю «LINQ to Entities» не распознает метод «System.Collections.Generic.List'1 [<> f__AnonymousType1'2 [System.String, System.Int32]] ToList [<> f__AnonymousType1'2] (System.Collections.Generic.IEnumerable'1 [<> f__AnonymousType1'2 [System.String, System.Int32]]) ', и этот метод не может быть переведен в выражение хранилища. «Спасибо за помощь! – erdomke

Смежные вопросы