Стремительная загрузка 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 легко загрузить эти поля для меня? Нужно ли выполнять простое объединение в моих запросах? Или есть другой способ?

http://img245.imageshack.us/img245/5631/linqtosql.jpg

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.

Другие вопросы по тегам