2017-01-06 5 views
0

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

База данных выглядит следующим образом:

Contacts - Id (P), Name, Surname, Address; 
Emails - EntryId (P), PersonId, Email1; 
Telephones - EntryId (P), PersonId, Telephone1; 
Tags - EntryId (P), PersonId, Tag1; 

(где P означает первичный ключ и PersonId всегда соответствующий идентификатор из таблицы контактов, лиц, чьи сообщения электронной почты,)

Я не подключены мои таблицы в любом случае, я просто approched Email человека с идентификатором ID, как это, например:

var mailsById = contactsData.Emails.Where(x => x.PersonId == ID).ToList(); 

Теперь я понял, что я должен, возможно, добавить внешний ключ к таблицам Эму ils, телефоны, теги, которые были бы PersonId, подключенные к Id из таблицы Contacts. Поэтому я добавил это таблица definitons на сообщения электронной почты:

CONSTRAINT [FK_Emails_Contacts] FOREIGN KEY ([PersonId]) REFERENCES [dbo].[Contacts] ([Id]) 

(то же самое с телефонами и тегами)

Все шло хорошо, на диаграмме EDMX теперь показывает (1, *) соединения между контактами стола и каждый другую таблицу (которую я хотел), но теперь я получаю 500 (Внутренняя ошибка сервера) по следующей функции. Функция возвращает полную информацию обо всех контактах в базе данных (во внешнем интерфейсе у меня есть таблица Name-Surname-Address-Emails-Telephones-Tags, вот почему я соединяю все таблицы из базы данных в один список).

public JsonResult getAll() 
    { 
     using (ContactsDBEntities contactsData = new ContactsDBEntities()) 
     { 
      List<Contact_Info> completeList = new List<Contact_Info>(); 
      var contacts = contactsData.Contacts; 
      var emails = contactsData.Emails; 
      var telephones = contactsData.Telephones; 
      var tags = contactsData.Tags; 

      //GroupJoin: 
      //Outer.GroupJoin(Inner, outer => key, inner => key, (outer, inner) => result) 

      //first join joins contacts table with emails table 
      var contactList = contacts.GroupJoin(emails, 
       contact => contact.Id, 
       email => email.PersonId, 
       (contact, email) => new 
       { 
        Id = contact.Id, 
        Name = contact.Name, 
        Surname = contact.Surname, 
        Address = contact.Address, 
        Email = email 
       }); 

      //second join joins telephones to the existing contacts-emails list 
      var contactList2 = contactList.GroupJoin(telephones, 
       contact => contact.Id, 
       telephone => telephone.PersonId, 
       (contact, telephone) => new 
       { 
        Id = contact.Id, 
        Name = contact.Name, 
        Surname = contact.Surname, 
        Address = contact.Address, 
        Email = contact.Email, 
        Telephone = telephone 
       }); 

      //third join creates the needed contacts-emails-telephones-tags list 
      var contactList3 = contactList2.GroupJoin(tags, 
       contact => contact.Id, 
       tag => tag.PersonId, 
       (contact, tag) => new 
       { 
        Id = contact.Id, 
        Name = contact.Name, 
        Surname = contact.Surname, 
        Address = contact.Address, 
        Email = contact.Email, 
        Telephone = contact.Telephone, 
        Tag = tag 
       }); 

      //contactList3 to completeList 
      foreach(var contact in contactList3) 
      { 
       Contact_Info temp = new Contact_Info(); 
       temp.Id = contact.Id; 
       temp.Name = contact.Name; 
       temp.Surname = contact.Surname; 
       temp.Address = contact.Address; 
       foreach (var em in contact.Email) 
       { 
        temp.Emails.Add(em); 
       } 
       foreach (var tel in contact.Telephone) 
       { 
        temp.Telephones.Add(tel); 
       } 
       foreach (var tag in contact.Tag) 
       { 
        temp.Tags.Add(tag); 
       } 
       completeList.Add(temp); 
      } 

      return Json(completeList, JsonRequestBehavior.AllowGet);     
     } 
    } 

не Это мой класс Contact_Info, который используется в этой функции:

public class Contact_Info 
    { 
     public Contact_Info() {} 

     public Contact_Info (string name, string surname, string address, List<Email> emails, List<Telephone> telephones, List<Tag> tags) 
     { 
      Name = name; 
      Surname = surname; 
      Address = address; 
      Emails = emails; 
      Telephones = telephones; 
      Tags = tags; 
     } 

     public int Id; 
     public string Name; 
     public string Surname; 
     public string Address; 
     public List<Email> Emails = new List<Email>(); 
     public List<Telephone> Telephones = new List<Telephone>(); 
     public List<Tag> Tags = new List<Tag>(); 
    } 

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

Можете ли вы сказать мне, что мне нужно изменить в рабочем приложении, если я изменил эти свойства внешних ключей таблиц? Слишком поздно делать это сейчас (т. Е. Требует радикального изменения моего кода) и насколько важны ограничения внешнего ключа здесь? Это мое первое использование баз данных в более сложном коде, поэтому, пожалуйста, поймите, если я сделал некоторые просьбы, не догадываясь об ошибках :)

Большое спасибо!

+0

На какой строке вы получаете эту ошибку об экземпляре ObjectContext, которая больше не может использоваться для операций, требующих подключения.? – CodingYoshi

+0

@CodingYoshi Хм, я не могу его найти, возможно ли, что на какой строке ошибка не возникает? – Filomena

+0

Когда вы отлаживаете, вы получаете ошибку до того, как метод действия будет завершен или после? – CodingYoshi

ответ

0

Если свойства навигации существуют между вашими объектами (т. Е. Вы создали edmx из базы данных и существуют ограничения FK), вам не нужно получать объекты отдельно, а затем присоединяться к ним. Просто используйте Include():

var contacts = contactsData.Contacts 
     .Include(x=>x.Emails) 
     .Include(x=>x.Telephones) 
     .Include(x=>x.Tags) 
     .ToList(); 

Я думаю, что Include является частью пространства имен System.Data.Entity.

+0

Я добавил System.Data.Entity имена и переписали функцию моего GETALL(), так что теперь это выглядит следующим образом: 'общественного JsonResult GETALL() { использование (ContactsDBEntities contactsData = новые ContactsDBEntities()) { вар контакты = contactsData.Contacts .INCLUDE (x => x.Emails) . Включить (x => x.Telephones) .Include (x => x.Tags) .ToList(); возвращение Json (контакты, JsonRequestBehavior.AllowGet); } } ' – Filomena

+0

Он по-прежнему возвращает ошибку, на этот раз выход является: _A циклическая ссылка была обнаружена при сериализации объекта типа«System.Data.Entity.DynamicProxies.Contact_55F0F20179BF8BAB1AC8CFFF6A7F318746B8C25429864C6FAE931BBF884EB6E3»._ – Filomena

+0

Таким образом, вы получаете данные и сериализация, но родитель имеет ссылку на дочерний элемент, а у ребенка есть ссылка на родителя. Поэтому, когда он сериализуется, существует бесконечная циркулярная ссылка. Что вам нужно сделать, это перейти к каждой дочерней модели и добавить атрибут [JsonIgnore] к навигационному свойству, указывающему на родителя. Этот атрибут находится в пространстве имен newtonsoft. Это позволит сериализатору знать, что в дочерней модели нет необходимости сериализовать родителя. Если вы регенерируете свои модели из базы данных, вам нужно будет добавить атрибут еще раз. – ATerry