【问题标题】:Linq-to-SQL strange behaviourLinq-to-SQL 奇怪的行为
【发布时间】:2013-09-14 23:24:37
【问题描述】:

假设两个表Groups和Users如下

[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。这是怎么回事?我是不是搞错了?

【问题讨论】:

  • 您是否尝试将您的 Users.ID 设置为主键并自动递增?
  • 是的,Group.IDUser.ID 都是主键,Identity(或自动递增)。我什至尝试将Group.IDUser.ID 设置为uniqueidentifier,并将它们的默认值设置为NewID()。但结果和描述的一样。
  • 我想问题不在于您的 UserId dbType,我认为在您的插入 (f3) 上,它会尝试插入组以及用户,而不是简单地添加具有组的用户id(如 f2)。我认为您必须选择组,然后将用户附加到它。

标签: c# linq linq-to-sql


【解决方案1】:

我猜是因为你在 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,而不是为每个方法创建一个新的。

【讨论】:

  • 谢谢,我希望有一个更好的解决方案。事实上,我决定使用 Linq-to-SQL 设计器作为具有 100 多个表的数据库的 ORM,并且我已经实现了存储库模式。现在我必须修改大多数存储库类的 Add 方法。没有更好的解决方案吗?
【解决方案2】:
Group = group,

在 f3 中,您将组的实例附加到用户。然后你告诉 datacontext 插入用户。因为有一个组连接到用户,并且数据上下文当前没有跟踪该组,所以它假设该组也需要插入。

【讨论】:

  • 谢谢,正如我在对@sgmoore 的评论中提到的那样,将对象附加到数据上下文听起来并不是一个完美的解决方案。是否有任何通知机制可以在其他实例发生更改时通知数据上下文?
  • 当您想通过一次调用 submitchanges 来插入/更新实例图时,datacontext 的行为非常棒。如果要管理一个数据上下文的实例跟踪,请对应该开始跟踪的实例使用重载的 Attach,或者对它已经跟踪的实例使用重载的 Refresh。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-15
  • 1970-01-01
  • 1970-01-01
  • 2011-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多