C# Linq到SQL的奇怪行为

C# Linq到SQL的奇怪行为,c#,linq,linq-to-sql,C#,Linq,Linq To 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是用户的外键 然后,我使用LINQtoSQL类设计器创建相关类,并将以下类添加

假设两个表组和用户如下

[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是用户的外键

然后,我使用LINQtoSQL类设计器创建相关类,并将以下类添加到项目中

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);
        }
    }
}

现在如果我打电话

DB.Group group = f1();
f2(group, "john");
f2(group, "bob");
然后一切都会好起来但如果我打电话

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

它抛出一个异常“插入时名称已存在”。事实上,OnValidate已被调用,它检测到组表的重复名称。奇怪的行为是在将新用户插入表时调用OnValidate。发生什么事?我犯了一个错误吗?

我猜,因为您正在f3中创建一个新的DataContext,所以它假定您希望将组作为新记录插入

您可以手动将组附加到新的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,而不是为每个方法创建一个新的DataContext

Group = group,

在f3中,您将组的实例附加到用户。然后告诉datacontext插入用户。由于有一个组连接到该用户,并且datacontext当前未跟踪该组,因此它假定该组也需要插入。

您是否尝试过使用自动增量将Users.ID设置为主键?是的,
group.ID
user.ID
都是主键和
Identity
(或自动增量). 我甚至尝试过将
Group.ID
User.ID
设置为
uniqueidentifier
,并将它们的默认值设置为
NewID()
。但结果与所描述的相同。我想问题不在UserId dbType上,我认为在insert(f3)上,它尝试插入组和用户,而不是简单地添加具有组id的用户(如f2)。我认为您必须选择该组,然后将用户附加到该组。谢谢,我希望有更好的解决方案。事实上,我决定使用LINQtoSQLDesigner作为包含100多个表的数据库的ORM,并且我已经实现了一个存储库模式。现在我必须修改大多数存储库类的Add方法。没有更好的解决方案吗?谢谢,正如我在@sgmoore-answer的评论中提到的,将对象附加到datacontext听起来不是一个完美的解决方案。当其他实例发生更改时,是否有任何通知机制可以通知datacontext?当您希望通过一次submitchanges调用插入/更新实例图时,datacontext的行为非常好。如果要管理一个datacontext的实例跟踪,请对其应开始跟踪的实例使用Attach重载,或对其已跟踪的实例使用刷新重载。
Group = group,