EF生成的SQL中的列名错误无效

时间:2017-07-13 01:05:32

标签: c# sql entity-framework ef-fluent-api

下面你可以看到SQL应该使用[ClassId1]而不是[Class1_ClassId]加入,因为后者不存在。

我很确定我可以使用Fluent API来纠正这个问题但不确定使用哪种方法。

生成SQL

SELECT ...
FROM [dbo].[School] AS [Extent1]
LEFT OUTER JOIN [dbo].[Student] AS [Extent2] ON [Extent1].[SchoolId] = [Extent2].[SchoolId]
LEFT OUTER JOIN [dbo].[Class] AS [Extent3] ON [Extent2].[Class1_ClassId] = [Extent3].[ClassId]
LEFT OUTER JOIN [dbo].[Class] AS [Extent4] ON [Extent2].[Class2_ClassId] = [Extent4].[ClassId]
WHERE ...   

School
- SchoolId
- Name
- StudentId

Student
- StudentId
- Name
- Class1Id
- Class2Id

Class
- ClassId
- Name

模型

public class School
{
    [Required]
    public long SchoolId { get; set; }

    [Required]
    public string Name { get; set; }

    [Required]
    public long StudentId { get; set; }

    public virtual Student Student { get; set; }
}

public class Student
{
    [Required]
    public long StudentId { get; set; }

    [Required]
    public string Name { get; set; }

    [Required]
    public long ClassId1 { get; set; }

    public long? ClassId2 { get; set; }

    public virtual Class Class1 { get; set; }
    public virtual Class Class2 { get; set; }
}

public class Class
{
    [Required]
    public long ClassId { get; set; }

    [Required]
    public string Name { get; set; }
}

2 个答案:

答案 0 :(得分:3)

[Required]
public long ClassId1 { get; set; }

public long? ClassId2 { get; set; }

public virtual Class Class1 { get; set; }
public virtual Class Class2 { get; set; }

您尚未设置这些属性之间的任何关系。由于您还没有为Class1Class2定义外键列,因此它会为您创建它们:Class1_ClassIdClass2_ClassId。创建迁移应该为您创建这些列;但是您最终会得到重复项(例如Class1IdClass1_ClassId)。

相信如果名称以Id结尾,则EntityFramework将解析属性之间的关系。这意味着您的设置应该是:

[Required]
public long Class1Id { get; set; }

public long? Class2Id { get; set; }

public virtual Class Class1 { get; set; }
public virtual Class Class2 { get; set; }

然而,我发现明白它更好 - 纯粹是为了可读性并确保EF不会试图变得太聪明。我这样写:

[Required]
public long ClassId1 { get; set; }

public long? ClassId2 { get; set; }

[ForeignKey("ClassId1")]
public virtual Class Class1 { get; set; }
[ForeignKey("ClassId2")]
public virtual Class Class2 { get; set; }

这应该在数据库中正确设置外键关系。

答案 1 :(得分:0)

我认为实体框架是从你的linq构造这个SQL的,因为模型中类之间的关系不清楚。

根据您的模型,School只有一个StudentStudent不知道他参加了哪个School,并且必须拥有一个Class class {1}},可能还有第二个。 School不知道Students是哪个ClassSchool中的Students

您确定您的型号吗?

我认为School会有零个或多个Classesclass也有零个或多个School。每个Student都是Classes中的一个类。

在数据库术语中,这是典型的一对多关系。见Entity Framework Configure One-to-Many Relationship

此外,Class出现零个或多个Studentsclass School { public int Id {get; set;} // a School has many Students: public virtual ICollection<Student> Students {get; set;} // a School has many Classes: public virtual ICollection<Class> Classes {get; set;} ... } public class Student { public int Id {get; set;} // A student belongs to one School via Foreign Key public int SchoolId {get; set;} public virtual School School {get; set;} // A student attends many classes public virtual ICollection<Class> Classes {get; set;} ... } class Class { public int Id {get; set;} // a class belongs to one School via foreign key: public int SchoolId {get; set;} public virtual School School {get; set;} // a class has many Students public virtual ICollection<Student> Students {get; set;} ... } 有一个或多个class MyDbContext : DbContext { public DbSet<School> Schools {get; set;} public DbSet<Student> Students {get; set;} public DbSet<Class> Classes {get; set;} }

在数据库术语中,这是典型的多对多关系。请参阅:Entity Framework configure many-to-many relationship

这些文章还描述了学校,学生和学生。总结类定义应该是:

Class

在此之后,DbContext将如下:

Classs

如果你这样建模,实体框架将自动识别学校和学生之间的一对多关系,并为它创建适当的外键。它还将识别学生和班级之间的多对多关系。它甚至会为多对多创建一个表,这在LINQ查询中是不需要的。

Entity Framework uses default conventions如果您遵循它们,您将无需告诉模型有关表名和列名,主键和外键等信息。

回到你的问题

您想告诉您的模型它应该为属性使用某个列名,而不是它从您的类关系构造的列名。

这可以使用您班级中的数据注释,或使用DbContext中的Fluent API来完成。我更喜欢使用Fluent Api,因为它允许您在不同的数据库结构中使用相同的类而无需更改类。如果您需要不同的表名,或主键的不同名称,小数的不同精度等,您所要做的就是创建一个新的DbContext。您不必更改课程,课程用户也不会注意到更改。

Fluent API is described here.

在您的情况下:指定表名而不是默认表名。

在我的示例中,A Classes将放在表格 class MyDbContext : DbContext { public DbSet<School> Schools {get; set;} public DbSet<Student> Students {get; set;} public DbSet<Class> Classes {get; set;} protected override void OnModelCreating(DbModelBuilder modelBuilder) { // Entity Class should be put in table Classes modelBuilder.Entity<Class>().ToTable("Classes"); // property Student.ClassId in column "ClassId1" modelBuilder.Entity<Student>() // from class Student .Property(student => student.ClassId) // take property ClassId .HasColumnName("ClassId1"); // give it the column name "ClassId1" } } 中,当然您在表struct myTempSubStruct { u32 v1; u16 v2; u8 v3; }; struct myTempStruct { u8 v4; u8 v5; myTempSubstruct v6; }; 中需要它:

from robot.libraries.BuiltIn import BuiltIn

class generated_messages(object):

    ROBOT_LIBRARY_SCOPE = 'GLOBAL'

    def __init__(self):
        self.syscom = BuiltIn().get_library_instance('syscom_rammbock')

    def myStruct(self, name):
        self.syscom.new_struct('myStruct', name)
        self.myTempStruct('myTempStruct')
        self.syscom.end_struct()

    def myTempReq(self):
        return myStruct