Стремительная загрузка Linq to SQL Entities в самоссылающуюся таблицу
У меня есть 2 связанных Linq to SQL вопросов. Пожалуйста, посмотрите на изображение ниже, чтобы увидеть, как выглядит моя модель.
Вопрос 1
Я пытаюсь понять, как стремиться загрузить User.AddedByUser
поле на моем User
класс / таблица. Это поле создается из отношения на User.AddedByUserId
поле. Таблица содержит ссылки на себя, и я пытаюсь выяснить, как получить Linq для SQL, чтобы загрузить User.AddedByUser
свойство охотно, то есть всякий раз, когда любой User
сущность загружается / извлекается, она также должна извлекать User.AddedByUser и User.ChangedByUser. Тем не менее, я понимаю, что это может стать рекурсивной проблемой...
Обновление 1.1:
Я попытался использовать DataLoadOptions следующим образом:
var options = new DataLoadOptions();
options.LoadWith<User>(u => u.ChangedByUser);
options.LoadWith<User>(u => u.AddedByUser);
db = new ModelDataContext(connectionString);
db.LoadOptions = options;
Но это не работает, я получаю следующее исключение в строке 2:
System.InvalidOperationException occurred
Message="Cycles not allowed in LoadOptions LoadWith type graph."
Source="System.Data.Linq"
StackTrace:
at System.Data.Linq.DataLoadOptions.ValidateTypeGraphAcyclic()
at System.Data.Linq.DataLoadOptions.Preload(MemberInfo association)
at System.Data.Linq.DataLoadOptions.LoadWith[T](Expression`1 expression)
at i3t.KpCosting.Service.Library.Repositories.UserRepository..ctor(String connectionString) in C:\Development\KP Costing\Trunk\Code\i3t.KpCosting.Service.Library\Repositories\UserRepository.cs:line 15
InnerException:
Исключение вполне очевидно: граф объектов не может быть циклическим. Кроме того, предполагая, что строка 2 не выдает исключение, я уверен, что строка 3 будет, поскольку они являются дублирующими ключами.
Обновление 1.2:
Следующее также не работает (не используется в сочетании с обновлением 1.1 выше):
var query = from u in db.Users
select new User()
{
Id = u.Id,
// other fields removed for brevityy
AddedByUser = u.AddedByUser,
ChangedByUser = u.ChangedByUser,
};
return query.ToList();
Выдает следующее, не требующее пояснений исключение:
System.NotSupportedException occurred
Message="Explicit construction of entity type 'i3t.KpCosting.Shared.Model.User' in query is not allowed."
Я сейчас действительно в недоумении, как решить эту проблему. Пожалуйста помоги!
вопрос 2
На каждой другой таблице в моей БД и, следовательно, на Linq to SQL, у меня есть два поля: Entity.ChangedByUser
(связано с Entity.ChangedByUserId
внешний ключ / отношения) и Entity.AddedByUser
(связано с Entity.AddedByUserId
внешний ключ / отношения)
Как мне заставить Linq to SQL легко загрузить эти поля для меня? Нужно ли выполнять простое объединение в моих запросах? Или есть другой способ?
3 ответа
Может быть, вы могли бы попытаться сделать шаг назад и посмотреть, что вы хотите сделать с отношениями? Я предполагаю, что вы хотите отобразить эту информацию пользователю, например, "изменено Iain Galloway 8 часов назад".
Может ли что-то вроде следующей работы?:-
var users = from u in db.Users
select new
{
/* other stuff... */
AddedTimestamp = u.AddedTimestamp,
AddedDescription = u.AddedByUser.FullName,
ChangedTimestamp = u.ChangedTimestamp,
ChangedDescription = u.ChangedByUser.FullName
};
Я использовал анонимный тип для (имо) ясности. Вы можете добавить эти свойства к своему типу пользователя, если хотите.
Что касается вашего второго вопроса, ваш обычный LoadWith(x => x.AddedByUser) и т. Д. Должен работать просто отлично - хотя я предпочитаю хранить строку описания непосредственно в базе данных - у вас есть компромисс между обновлением описания когда ChangedByUser.FullName изменяется и приходится делать что-то сложное и, возможно, нелогичное, если ChangedByUser удаляется (например, ON DELETE CASCADE или имеет дело с нулевым ChangedByUser в вашем коде).
Любой тип циклов просто не допускается. Так как LoadWith<T>
или же AssociateWith<T>
применяются к каждому типу в контексте, нет внутреннего способа предотвратить бесконечный цикл. Точнее, он просто запутался в том, как создать SQL, поскольку SQL Server не имеет CONNECT BY
и CTE действительно прошли то, что Linq может генерировать автоматически с помощью предоставленной среды.
Наилучший доступный вариант - вручную выполнить 1-уровневое объединение с пользовательской таблицей для обоих дочерних и анонимного типа, чтобы вернуть их. Извините, это не чистое / простое решение, но это действительно все, что доступно на данный момент с Linq.
Не уверен, что есть решение этой проблемы с Linq to Sql. Если вы используете Sql Server 2005, вы можете определить (рекурсивно-подобный) Stored Procecdure, который использует общие табличные выражения, чтобы получить желаемый результат, а затем выполнить его, используя DataContext.ExecuteQuery.