Linq - что делать, когда "Запросы с локальными коллекциями не поддерживаются"

Я пытаюсь преобразовать SQL-запрос в Linq, и я получаю исключение:

System.NotSupportedException: запросы с локальными коллекциями не поддерживаются.

Итак, есть способ перефразировать запрос "законным" способом?

Спасибо за любые предложения,

Андерс, Дания

PS: Я видел "решение" для вызова .ToList() для любого запроса перед вызовом .Contains() - но это просто приведет к четырем отдельным запросам, правильно?

Внизу находится мой код, который не выполняется при выполнении.

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

Другими словами, пользователь должен иметь доступ, если выполнено одно из следующих условий:

  • Пользователь создал структуру (идентификатор "помечен" в запись структуры).
  • В таблице PermissionUsers существует запись, связывающая таблицу разрешений с таблицей пользователей.
  • В таблице PermissionGroups существует запись, связывающая таблицу Permissions с таблицей групп, и на нее ссылаются в таблицу UsersGroups, связывающую таблицу Users с таблицей Users.

Применение разрешений/ограничение результата для доступных элементов является относительно новой вещью, и мы хотели бы, чтобы база данных выполняла тяжелое растягивание;).

[TestFixture]
public class LinqTest : CommandBasedIntegrationTestBase
{
 [Test, Category("SuperIntegration"), RequiresSTAAttribute]
 public void TestThat()
 {
 DbIntegrationTestHelper.SetState();
 var dataContextProvider = ObjectFactory.GetInstance<idatacontextprovider>();
 const int userId = 1;
 var environment = ObjectFactory.GetInstance<istate>().DatabaseEnvironment;
 var dataClasses1DataContext = dataContextProvider.GetContext(environment);
 var idsByCreator = from r in dataClasses1DataContext.Structures where r.CreatedUserId == userId select r.StructureId;
 var idsByUserAccess = from r in dataClasses1DataContext.PermissionUsers where r.UserId == userId select r.StructureId;
 var idsOfGroupsContainingUser = from r in dataClasses1DataContext.UsersGroups where r.UserId == userId select r.GroupId;
 var idsByGroupAccess = from r in dataClasses1DataContext.PermissionGroups where idsOfGroupsContainingUser.Contains( r.GroupId ) select r.StructureId;
 var res = from s in dataClasses1DataContext.Structures
 where
 idsByCreator.Contains(s.StructureId) || 
 idsByUserAccess.Contains(s.StructureId) ||
 idsByGroupAccess.Contains(s.StructureId)
 select s;
 foreach (var structure in res)
 {
 Debug.WriteLine(structure.Name);
 }
 }
}
</istate></idatacontextprovider>
2 ответа

Попробуйте JOIN s, UNION s

Пример

var ctx = dataContextProvider.GetContext(environment);
var byCreator = from r in ctx.Structures where r.CreatedUserId == userId select r;
var byUserAccess = from r in ctx.PermissionUsers 
 join s in ctx.Structures on r.StructureId equals s.StructureId
 where r.UserId == userId select s;
var byGroups = from ug in ctx.UsersGroups 
 join pg in ctx.PermissionGroups on ug.GroupId equals pg.GroupId
 join s in ctx.Structures on pg.StructureId equals s.StructureId
 where ug.UserId == userId select s;
var res = byCreator.Union(byUserAccess).Union(byGroups);

Update

Я удалил ненужный вызов Distinct() в соответствии с комментарием @Magnus. Вызов Distinct() необходим только в том случае, если используется Concat() вместо Union().


Как я вижу, вы пытаетесь найти s.StructureId в таблицах базы данных и приносите их на прикладной уровень.

Возможно, вам лучше нажать весь свой логин в SQL Function или SP и получить окончательный результат только на уровне приложения?

licensed under cc by-sa 3.0 with attribution.