Понимание отношений «многие ко многим» и Entity Framework

Я пытаюсь понять Entity Framework, и у меня есть таблица «Пользователи» и таблица «Страницы». Они связаны отношением «многие ко многим» с соединительной таблицей «UserPages». Прежде всего, я хотел бы знать, правильно ли я разрабатываю эти отношения, используя «многие ко многим»: один пользователь может посещать несколько страниц, и каждую страницу могут посещать несколько пользователей..., так что я прав в использовании много2много?

Во-вторых, и это более важно, как я понял отношения m2m, таблицы User и Page не должны повторять информацию. т.е. должна быть только одна запись для каждого пользователя и каждой страницы. Но тогда в рамках сущности, как я могу добавить новые посещения одной и той же страницы для одного и того же пользователя? То есть я думал, что могу просто использовать метод Count() в IEnumerable, возвращаемый запросом LINQ, чтобы получить количество посещений пользователем определенной страницы.

Но я не вижу способа сделать это. В Linq to Sql я мог получить доступ к таблице соединений и добавить туда записи, чтобы отразить добавленные посещения определенной страницы определенным пользователем столько раз, сколько необходимо. Но в EF я не могу получить доступ к таблице соединений. Я могу перейти только от пользователя к коллекции страниц и наоборот.

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

Помогите, пожалуйста, понять, что я делаю не так...


person Anders    schedule 02.06.2010    source источник


Ответы (1)


Вы все делаете правильно.

В Entity Data Model (EDM) отношения Many-To-Many могут быть представлены с таблицей соединения или без нее, в зависимости от того, содержит ли она дополнительные поля. См. статью ниже для более подробной информации.


В вашем случае сущность Пользователь будет напрямую ссылаться на набор сущностей Страницы и наоборот, поскольку ваша модель не включает сопоставление для User_Page присоединиться к таблице.

Чтобы добавить посещения определенной страницы пользователя, вы можете, например, сделать что-то вроде:

using (var context = new YourEntityModelObjectContext())
{
     var page = context.Pages.FirstOrDefault(p => p.Url == "http://someurl");
     var user = context.Users.FirstOrDefault(u => u.Username == "someuser");

     user.Pages.Add(page);

     context.SaveChanges();
}

Или вы можете сделать это с другой стороны отношения:

using (var context = new YourEntityModelObjectContext())
{
     var page = context.Pages.FirstOrDefault(p => p.Url == "http://someurl");
     var user = context.Users.FirstOrDefault(u => u.Username == "someuser");

     page.Users.Add(user);

     context.SaveChanges();
}

В обоих случаях в таблицу соединения User_Page будет добавлена ​​новая запись.

Если вам нужно получить количество страниц, посещенных конкретным пользователем, вы можете просто сделать:

using (var context = new YourEntityModelObjectContext())
{
     var user = context.Users.FirstOrDefault(u => u.Username == "someuser");
     var visitCount = user.Pages.Count;
}

Связанные ресурсы:

person Enrico Campidoglio    schedule 02.06.2010
comment
Спасибо, но если я вас как-то не так понял, это не работает, я уже пробовал это. Я получаю это исключение: Невозможно обновить EntitySet 'UserPages', потому что у него есть DefiningQuery, а в элементе ‹ModificationFunctionMapping› нет элемента ‹InsertFunction› для поддержки текущей операции. Я не совсем уверен, что это значит, так как я новичок в EF... - person Anders; 03.06.2010
comment
Похоже, сущность UserPages сопоставляется с таблицей соединения между таблицами User и Page. Вам не нужно включать эту сущность в свою модель и вместо этого создавать прямое отношение «многие ко многим» между сущностями «Пользователь» и «Страница». Подробнее о том, как это сделать, читайте в этой статье: learnentityframework.com/LearnEntityFramework/tutorials/ - person Enrico Campidoglio; 03.06.2010
comment
Ну нет, в модели нет таблицы соединения, только классы User и Page. Таким образом, таблица UserPages, похоже, каким-то образом используется только в фоновом режиме. Я выбрал все таблицы, когда создавал Entity Data Model в диалоговом окне, но я догадался, что, если я этого не сделаю, связь не будет включена в модель? Но опять же, несмотря на то, что я выбрал все таблицы, таблица соединений не была включена в сгенерированную модель... - person Anders; 03.06.2010
comment
Я понимаю. Таблица соединений не является частью концептуальной модели (CSDL), но включена в модель хранения (SSDL). Оба являются частью модели EDM. Исключение, которое вы описали ранее, вызвано тем фактом, что таблица соединения не имеет первичного ключа, определенного в базе данных. В этом случае Visual Studio создаст представление в модели хранения (DefiningQuery), которое по умолчанию нельзя обновить. Мое предложение состоит в том, что вы определяете первичный ключ для таблицы соединений в базе данных, а затем обновляете свою модель (в конструкторе EDM щелкните правой кнопкой мыши и выберите «Обновить модель из базы данных»). - person Enrico Campidoglio; 03.06.2010
comment
Для всех, кто просматривает этот пост: рассмотрите возможность использования составного первичного ключа. Я только что столкнулся с этой проблемой с таблицей соединений без первичного ключа и потратил 30 минут, прежде чем обратиться за помощью к uber-dev и получить это предложение. . . который работал чудесно! Простое добавление обычного первичного ключа в таблицу соединений привело к другим ошибкам для меня, плюс это действительно было кладжом. - person Ethel Evans; 21.12.2010