2013-09-14 4 views
0

Предположим, две таблицы групп и пользователей следующим образомLinq к SQL странное поведение

[Groups] ([Id] [int] NOT NULL, [Name] [nchar](50) NULL); 
[Users] ([Id] [int] NOT NULL, [Name] [nchar](50) NULL, [GroupId] [int] NOT NULL); 
FOREIGN KEY([GroupId]) REFERENCES [Groups] ([Id]) 

Где GroupID является внешним ключом для пользователей.

Затем я использую Linq-to-SQL класса дизайнера создать соответствующие классы и добавить следующий класс в проект

public partial class Group 
{ 
    public override int GetHashCode() 
    { 
     return (Id.GetHashCode()); 
    } 

    public override bool Equals(object item) 
    { 
     if ((item == null) || (item is System.DBNull)) 
      return (false); 
     else 
     { 
      var temp = item as Group; 
      if (temp == null) 
       return (false); 
      else 
       if (_Id.Equals(0)) 
        return (_Name.Equals(temp.Name)); 
       else 
        return (_Id == temp.Id); 
     } 
    } 

    partial void OnValidate(System.Data.Linq.ChangeAction action) 
    { 
     var dc = new DB.DataContext(); 

     if (action == System.Data.Linq.ChangeAction.Insert) 
      if (dc.Groups.Count(o => o.Name.Equals(_Name)) != 0) 
       throw new Exception("Name Already Exist On Insert"); 

     if (action == System.Data.Linq.ChangeAction.Update) 
      if (dc.Groups.Count(o => (!o.Id.Equals(_Id) && o.Name.Equals(_Name))) != 0) 
       throw new Exception("Name Already Exist On Update"); 
    } 
} 

public partial class User 
{ 
    public override int GetHashCode() 
    { 
     return (Id.GetHashCode()); 
    } 

    public override bool Equals(object item) 
    { 
     if ((item == null) || (item is System.DBNull)) 
      return (false); 
     else 
     { 
      var temp = item as User; 
      if (temp == null) 
       return (false); 
      else 
       if (_Id.Equals(0)) 
        return (_Name.Equals(temp.Name)); 
       else 
        return (_Id == temp.Id); 
     } 
    } 
} 

и

public static DB.Group f1() 
{ 
    DB.DataContext dc = new DB.DataContext(); 
    if (dc.Groups.Count() == 0) 
    { 
     DB.Group group = new DB.Group() { Name = "admins" }; 
     dc.Groups.InsertOnSubmit(group); 
     dc.SubmitChanges(); 
    } 
    return dc.Groups.First(); 
} 

public static void f2(DB.Group group, string name) 
{ 
    DB.DataContext dc = new DB.DataContext(); 
    DB.User user = new DB.User() { Name = name, GroupId = group.Id, }; 
    dc.Users.InsertOnSubmit(user); 
    dc.SubmitChanges(); 
} 

public static void f3(DB.Group group, string name) 
{ 
    DB.DataContext dc = new DB.DataContext(); 
    DB.User user = new DB.User() { Name = name, Group = group, }; 
    dc.Users.InsertOnSubmit(user); 
    dc.SubmitChanges(); 
} 

теперь, если я называю

DB.Group group = f1(); 
f2(group, "john"); 
f2(group, "bob"); 

тогда все будет хорошо, но если я позвоню

DB.Group group = f1(); 
f2(group, "john"); 
f3(group, "bob"); 

он выдает исключение «Имя уже существует во вставке». Фактически, OnValidate был вызван, и он обнаруживает повторяющиеся имена для таблицы групп. Странное поведение заключается в том, что OnValidate вызывается, когда новый пользователь будет вставлен в таблицу. Что происходит? Я сделал ошибку?

+0

Вы пытались настроить свой User.ID на первичный ключ с автоматическим приращением? – Shide

+0

Да, и 'Group.ID', и' User.ID' являются первичными ключами и 'Identity' (или автоматическим приращением). Я даже попробовал его с параметрами 'Group.ID' и' User.ID' с 'uniqueidentifier', а их значения по умолчанию -' NewID() '. но результат такой же, как описано. – anonim

+0

Я думаю, проблема не в вашем UserId dbType, я думаю, что на вашей вставке (f3) он пытается вставить группу, а также пользователя, вместо простого добавления пользователя с идентификатором группы (например, f2). Думаю, вам нужно будет выбрать группу, а затем присоединить к ней пользователя. – Shide

ответ

0

Я предполагаю, что, поскольку вы создаете новый DataContext в f3, он предполагает, что вы хотите вставить группу в новую запись.

Вы можете вручную прикрепить группу к новому DataContext, чтобы она не пыталась вставить его.

public static void f3(DB.Group group, string name) 
{ 
    DB.DataContext dc = new DB.DataContext(); 
    dc.Groups.Attach(group); 
    DB.User user = new DB.User() { Name = name, Group = group, }; 
    dc.Users.InsertOnSubmit(user); 
    dc.SubmitChanges(); 
} 

В качестве альтернативы вы можете создать один DataContext, а не создавать новый для каждого метода.

+0

Спасибо, я бы предпочел иметь лучшее решение для этого. На самом деле я решил использовать конструктор Linq-to-SQL в качестве ORM для базы данных с более чем 100 таблицами, и я реализовал шаблон хранилища. Теперь мне нужно изменить метод Add для большинства классов репозитория. Разве нет лучшего решения для этого? – anonim

0
Group = group, 

В f3 вы прикрепили экземпляр группы к пользователю. Затем вы сказали datacontext, чтобы вставить пользователя. Поскольку группа подключена к пользователю, а datacontext в настоящее время не отслеживает эту группу, предполагается, что группа также должна быть вставлена.

+0

Спасибо, как я упомянул в комментарии к @sgmoore, ответ, прикрепляющий объекты к datacontext, не кажется идеальным решением. Есть ли какой-либо механизм уведомления для datacontext для уведомления при изменении других экземпляров? – anonim

+0

Поведение datacontext замечательно, если вы хотите вставить/обновить граф экземпляров одним вызовом для подписок. Если вы хотите управлять отслеживанием экземпляра одного файла datacontext, используйте перегрузку Attach для экземпляров, которые он должен начать отслеживать, или перегрузка Refresh экземпляров, которые он уже отслеживает. –

Смежные вопросы