C# LINQ生成不正确的SQL(引用不存在的表)
MVC3项目,先使用LINQ转换实体,然后使用实体框架4代码 在另一篇文章中,我在创建LINQ语句以返回数据子集方面得到了帮助 LINQ在语法上是正确的,可以编译,但会生成不正确的SQL。具体来说,它引用了一个不存在的表。如果我更正表名,它将返回正确的数据,因此LINQ似乎是正确的 注意:为了避免这篇长文章变得更长,我不会发布对象类Product、Tag和ProductTag,但它们列在我前面的问题中: 林克: 以下是不正确和正确的SQL代码 错误的SQL引用了不存在的表C# LINQ生成不正确的SQL(引用不存在的表),c#,asp.net-mvc-3,linq,entity-framework-4,ef-model-first,C#,Asp.net Mvc 3,Linq,Entity Framework 4,Ef Model First,MVC3项目,先使用LINQ转换实体,然后使用实体框架4代码 在另一篇文章中,我在创建LINQ语句以返回数据子集方面得到了帮助 LINQ在语法上是正确的,可以编译,但会生成不正确的SQL。具体来说,它引用了一个不存在的表。如果我更正表名,它将返回正确的数据,因此LINQ似乎是正确的 注意:为了避免这篇长文章变得更长,我不会发布对象类Product、Tag和ProductTag,但它们列在我前面的问题中: 林克: 以下是不正确和正确的SQL代码 错误的SQL引用了不存在的表 [dbo].[Tag
[dbo].[TagProduct]
以及一个格式不正确的字段
[ExtentN].[Tag_TagId]
如果我将它们更正为[dbo].[ProductTag]和[ExtentN].[TagId],SQL将正确执行并返回正确的数据
LINQ生成了错误的SQL
正确的SQL
同样,SQL中唯一的变化是
[dbo].[TagProduct] changed to [dbo].[ProductTag]
[ExtentN].[Tag_TagId] changed to [ExtentN].[TagId]
注意,我已经确保数据库中没有名为dbo.TagProduct的对象,并且在我的代码中没有对TagProduct的引用,也从来没有
我的LINQ语句中是否有问题,或者这是一个LINQ错误?我完全可以放弃它,只创建一个存储过程,但我更愿意找到一个修复方法
感谢并为这篇冗长的帖子道歉
编辑
这个问题原来是一个有缺陷的实体模型,在多对多关系中的表之间有过多和不必要的导航属性。Slauma的详细回答是理解发生了什么的关键
新模式如下:
public class Product
{
.
.
//public virtual List<Tag> Tags { get; set; } // <--removed
public virtual List<ProductTag> ProductTags { get; set; }
}
public class ProductTag
{
.
.
public virtual Product Product { get; set; }
public virtual Tag Tag { get; set; }
}
public class Tag
{
.
.
//public virtual List<Product> Products { get; set; } // <--removed
public virtual List<ProductTag> ProductTags { get; set; }
}
如果链接帖子中的模型中没有任何Fluent API中的其他映射,则生成的SQL是正确的。为什么? 为了清楚起见,我复制了您的模型,其中包含相关的导航属性和标记,它们属于一个整体:
public class Tag
{
public int TagId { get; set; }
public virtual List<Product> Products { get; set; } /* 1 */
public virtual List<ProductTag> ProductTags { get; set; } /* 2 */
}
public class Product
{
public int ProductId { get; set; }
public virtual List<Tag> Tags { get; set; } /* 1 */
}
public class ProductTag
{
public int ProductTagId { get; set; }
public int ProductId { get; set; }
public int TagId { get; set; }
public virtual Product Product { get; set; } /* 3 */
public virtual Tag Tag { get; set; } /* 2 */
}
但这会产生问题,因为您已经有了一个ProductTag实体,它显然已经有了相应的表ProductTag。这不能同时成为多对多关系的联接表。联接表必须有另一个名称,如x.ToTableProductTagJoinTable
我想知道你是否真的想要这三种关系。或者,为什么希望表名ProductTag属于ProductTag实体?查询中根本不涉及此表和实体
编辑
更改模型的建议:除了多对多联接表所需的字段外,ProductTag实体不包含任何其他字段。因此,我将其映射为一个纯多对多关系。这意味着:
从模型中删除ProductTag实体类
从标记类中删除ProductTags导航属性
如上所示,在Fluent API中定义与名为ProductTag的联接表对应的映射,该联接表有两列ProductId和TagId,这两列构成复合主键,分别是Product和Tag表的外键
因此,在产品和标签之间只有一个多对多关系,而不是三个关系,我希望您的查询能够正常工作。如果您在链接文章中的模型中没有Fluent API中的任何其他映射,则生成的SQL是正确的。为什么? 为了清楚起见,我复制了您的模型,其中包含相关的导航属性和标记,它们属于一个整体:
public class Tag
{
public int TagId { get; set; }
public virtual List<Product> Products { get; set; } /* 1 */
public virtual List<ProductTag> ProductTags { get; set; } /* 2 */
}
public class Product
{
public int ProductId { get; set; }
public virtual List<Tag> Tags { get; set; } /* 1 */
}
public class ProductTag
{
public int ProductTagId { get; set; }
public int ProductId { get; set; }
public int TagId { get; set; }
public virtual Product Product { get; set; } /* 3 */
public virtual Tag Tag { get; set; } /* 2 */
}
但这会产生问题,因为您已经有了一个ProductTag实体,它显然已经有了相应的表ProductTag。这不能同时成为多对多关系的联接表。联接表必须有另一个名称,如x.ToTableProductTagJoinTable
我想知道你是否真的想要这三种关系。或者,为什么希望表名ProductTag属于ProductTag实体?查询中根本不涉及此表和实体
编辑
更改模型的建议:除了多对多联接表所需的字段外,ProductTag实体不包含任何其他字段。因此,我将其映射为一个纯多对多关系。这意味着:
从模型中删除ProductTag实体类
从标记类中删除ProductTags导航属性
如上所示,在Fluent API中定义与名为ProductTag的联接表对应的映射,该联接表有两列ProductId和TagId,这两列构成复合主键,分别是Product和Tag表的外键
因此,产品和标签之间只有一个多对多关系,而不是三个关系,我希望您的查询能够正常工作。Um,这不是HTML。。。那是SQL。。。听起来您的模型可能与您的模式过时了。看起来您在没有重新创建本应具有的数据库的情况下更改了模型
将错误的LINQ查询更改为我给您的正确查询…在指定HTML而不是SQL时说不出话来;编辑文章。此外,链方法查询中的剪切/粘贴错误。我试着把它转换成linq,这就是我想到的。无论哪种方式,两个版本(包括您的版本)都会生成相同的错误SQL并抛出运行时错误。至于已经过时的模型,我没有任何产品表或模型。我昨天刚刚创建了dbo.ProductTag及其模型。所以我不相信它过时了…嗯,那不是HTML。。。那是SQL。。。听起来你的模型可能与你的模式过时了。看起来你在没有重新创建数据库的情况下更改了模型。你应该将错误的LINQ查询更改为我给你的正确查询…无言地过度指定HTML而不是SQL;编辑文章。此外,链方法查询中的剪切/粘贴错误。我试着把它转换成linq,这就是我想到的。无论哪种方式,两个版本(包括您的版本)都会生成相同的错误SQL并抛出运行时错误。至于已经过时的模型,我没有任何产品表或模型。我昨天刚刚创建了dbo.ProductTag及其模型。所以我不认为它过时了……我不得不花一点时间来理解你的答案,然后我开始在应用程序的其他区域看到更多无效对象名dbo.TagProduct错误。就在那时,你的答案开始深入人心。我结束了从产品和标签中删除导航属性。必须重新构造gdoron提供的查询以反映这些更改,现在一切都正常了。我将编辑我的问题以显示最终产品。感谢您的帮助和详细的答复@约翰:我明白了。ProductTag实体中是否有其他标量属性?否则,产品和标签之间的多对多映射不需要它,但它也可以工作:我不得不花一点时间来理解您的答案,然后我开始在应用程序的其他区域看到更多无效对象名dbo.TagProduct错误。就在那时,你的答案开始深入人心。我结束了从产品和标签中删除导航属性。必须重新构造gdoron提供的查询以反映这些更改,现在一切都正常了。我将编辑我的问题以显示最终产品。感谢您的帮助和详细的答复@约翰:我明白了。ProductTag实体中是否有其他标量属性?否则,产品和标签之间的多对多映射不需要它,但它也可以工作:
public class Product
{
.
.
//public virtual List<Tag> Tags { get; set; } // <--removed
public virtual List<ProductTag> ProductTags { get; set; }
}
public class ProductTag
{
.
.
public virtual Product Product { get; set; }
public virtual Tag Tag { get; set; }
}
public class Tag
{
.
.
//public virtual List<Product> Products { get; set; } // <--removed
public virtual List<ProductTag> ProductTags { get; set; }
}
public class Tag
{
public int TagId { get; set; }
public virtual List<Product> Products { get; set; } /* 1 */
public virtual List<ProductTag> ProductTags { get; set; } /* 2 */
}
public class Product
{
public int ProductId { get; set; }
public virtual List<Tag> Tags { get; set; } /* 1 */
}
public class ProductTag
{
public int ProductTagId { get; set; }
public int ProductId { get; set; }
public int TagId { get; set; }
public virtual Product Product { get; set; } /* 3 */
public virtual Tag Tag { get; set; } /* 2 */
}
modelBuilder.Entity<Product>()
.HasMany(p => p.Tags)
.WithMany(t => t.Products)
.Map(x =>
{
x.MapLeftKey("ProductId");
x.MapRightKey("TagId");
x.ToTable("ProductTag");
});