LINQ to SQL和外键的基本误解

Posted

技术标签:

【中文标题】LINQ to SQL和外键的基本误解【英文标题】:Basic misunderstanding of LINQ to SQL and foreign keys 【发布时间】:2021-09-23 22:12:30 【问题描述】:

我正在处理一个更大的项目,但似乎无法让 LINQ to SQL 以我期望的方式工作。我创建了项目的一个简单子集,因此我可以使用 LinqPad 来确保我对它应该如何工作有一个基本的了解。

显然,我没有:我创建了两个非常简单的表 - customerjobcustomer 表有一个ID(自动增量)和一个NameJob 表有一个ID(ai)、一个Name 和一个CustomerID(ID 的外键)在customer 表中)。

当我对最初为空的数据库运行以下代码时:

void Main()

    string custName = "James";
    string[] jobNames = new string[] "Home Depot", "Menards", "Sam's Club" ;

    var cust = customer.FirstOrDefault(c => c.Name == custName);

    if (cust == null)
    
        cust = new customer
        
            Name = custName
        ;
        customer.InsertOnSubmit(cust);
    

    foreach(var jn in jobNames)
    
        if (!job.Any(j => j.Customer.Name == cust.Name && j.Name == jn))
            job.InsertOnSubmit(new job 
                Name = jn,
                Customer = cust
            );
    

    SubmitChanges();
    
    customer.Dump();
    job.Dump();

我希望最终在数据库中有 1 个客户和 3 个工作 - 这一切都很好。但是生成的 SQL 和客户 ID 的设置完全不是我所期望的:

SQL --

SELECT t0.ID, t0.Name
FROM customer AS t0
WHERE (t0.Name = @p0)
LIMIT 0, 1
-- p0 = [James]

SELECT COUNT(*) AS value
FROM job AS t0
LEFT OUTER JOIN customer AS t1
  ON (t1.ID = t0.CustomerID)
WHERE ((t1.Name = @p0) AND (t0.Name = @p1))
-- p0 = [James]
-- p1 = [Home Depot]

SELECT COUNT(*) AS value
FROM job AS t0
LEFT OUTER JOIN customer AS t1
  ON (t1.ID = t0.CustomerID)
WHERE ((t1.Name = @p0) AND (t0.Name = @p1))
-- p0 = [James]
-- p1 = [Menards]

SELECT COUNT(*) AS value
FROM job AS t0
LEFT OUTER JOIN customer AS t1
  ON (t1.ID = t0.CustomerID)
WHERE ((t1.Name = @p0) AND (t0.Name = @p1))
-- p0 = [James]
-- p1 = [Sam's Club]

INSERT INTO job(CustomerID, ID, Name)
VALUES (NULL, 0, @p0)
-- p0 = [Home Depot]

INSERT INTO job(CustomerID, ID, Name)
VALUES (NULL, 0, @p0)
-- p0 = [Menards]

INSERT INTO job(CustomerID, ID, Name)
VALUES (NULL, 0, @p0)
-- p0 = [Sam's Club]

INSERT INTO customer(ID, Name)
VALUES (0, @p0)
-- p0 = [James]

SELECT t0.ID, t0.Name
FROM customer AS t0

SELECT t0.CustomerID, t0.ID, t0.Name
FROM job AS t0

LinqPad 中的结果:

我认为 LINQ to SQL 的美妙之处在于我不必设法设置外键,并且我应该能够通过单击数据库来完成我在此处尝试执行的操作。我错过了什么?

编辑:所以我想我理解客户 ID 被设置为 NULL,因为生成的 SQL 在客户的 INSERT 之前对作业调用 INSERT,因此还没有 ID。为什么会这样做?此外,如果我再次运行相同的查询,我会在作业表中再获得三行,但 CustomerID 仍然设置为 NULL。

【问题讨论】:

第 1 步 - 考虑如何编写 SQL(提示 - 将涉及 IN)。 @mjwills 如果我要为这个简单的示例编写 SQL,我不确定我会在哪里使用 IN,除非您指的是一种简化我的 foreach 循环的方法,即几乎不是问题的重点。 这是使用 LinqPad 自动生成的数据上下文还是您自己的?看起来 Linq2Sql 认为 Customer 表依赖于 Job 表(我怀疑 customer.job 是单个 Job 而不是 EntitySet),因此需要在客户? 【参考方案1】:

Linq 查询没有问题。 检查数据库表关系

【讨论】:

我在 SQL Server 中重新创建了我的测试平台(正如您所做的那样),您是对的,代码完全符合我的预期。有谁知道为什么 mysql(实际上是 MariaDB)会有不同的行为? 问题出在参考。请检查外键是如何在数据库中创建的。 (抱歉对mysql没有太多经验)softwaretestinghelp.com/mysql-foreign-key-constraint

以上是关于LINQ to SQL和外键的基本误解的主要内容,如果未能解决你的问题,请参考以下文章

我是不是误解了 LINQ to SQL .AsEnumerable()?

LINQ to entity中的一些误解

请问SQL server 中的主键和外键的作用

SQL的主键和外键的作用

SQL中主键和外键的定义是啥???

问题 Datagridview 和外键和主键列