实体框架-无效的列名“ * _ID”


101

我将范围缩小到“代码优先”和“数据库优先” EF之间的某个问题,但是我不确定如何解决它。我会尽量保持清楚,但老实说我本人在这里缺少一些了解。这是实体框架4.4

我继承了一个使用Entity Framework的项目,但是删除了许多实际文件,没有任何实际方法可以返回。我重新添加了EF(首先是数据库),并复制了围绕该项目构建的T4设置。它生成了所有数据库模型的代码版本和一个DBContext代码文件。

如果我的连接字符串看起来像是“正常” .NET连接字符串,则会收到有关无效列的错误消息,名称“ ProcessState_ID”不存在。ProcessState_ID根本不在代码库中,也不在EDMX文件或任何其他文件中。这似乎是查询中的某些自动EF转换。

当我使连接字符串与实体框架模型匹配时,它可以正常工作。

现在,在尝试将前面的代码与Entity Framework匹配时,我想保留“普通” .NET连接字符串。

因此,我在这里有两个问题:1.从代码中的正常连接字符串转换为EF连接字符串的最佳方法是什么?2.这里有没有我想停止无效列名错误的其他修复程序?


3
如果你有一个导航属性只有一个get访问也会发生这种情况:public virtual Person Person { get; }
Şafak古尔

请注明答案
囚犯零

Answers:


90

检查是否有任何ICollections。

我想出的是,当您有一个引用表的ICollection且没有可查明的列时,它将为您创建一个尝试在表之间建立连接的列。这种情况特别发生在ICollection上,并促使我尝试解决这个问题。


43
只是要弄清楚这个答案,因为它对我的情况最准确(但直到发现问题后我才知道)。如果在检索Table时遇到与OtherTable_ID相关的错误,请转到OtherTable模型并确保其中没有ICollection <Table>。如果没有定义关系,则框架将自动假定您必须对OtherTable具有FK,并在生成的SQL中创建这些额外的属性。
路加福音

15
EF浪费了我4个小时
Nitin S

2
@NitinSawant那是吗?EF每天都要花4个小时来浪费我所有的重复和未附加的记录。
雅各布

@LUKE您的评论救了我。我是如此爱你:)
Amir Hossein Ahmadi

1
@LUKE我们需要的EF英雄,而不是我们应得的EF英雄。我爱你。
马修·杨

63

对于那些不立即了解其他两个答案的人(像我一样),这是迟到的条目。

所以...

EF尝试从PARENT TABLES KEY-REFERENCE映射到EXPECTED名称...并且由于...在数据库CHILD TABLE关系中,FOREIGN KEY名称已“更改或缩短” ...您将获得上面的消息。

(此修复程序在EF版本之间可能有所不同)

对我而言,解决方法是:
在模型中添加“ ForeignKey”属性

public partial class Tour
{
    public Guid Id { get; set; }

    public Guid CategoryId { get; set; }

    [Required]
    [StringLength(200)]
    public string Name { get; set; }

    [StringLength(500)]
    public string Description { get; set; }

    [StringLength(50)]
    public string ShortName { get; set; }

    [StringLength(500)]
    public string TourUrl { get; set; }

    [StringLength(500)]
    public string ThumbnailUrl { get; set; }

    public bool IsActive { get; set; }

    [Required]
    [StringLength(720)]
    public string UpdatedBy { get; set; }

    [ForeignKey("CategoryId")]
    public virtual TourCategory TourCategory { get; set; }
}

4
这对我有用。+1是我找到此答案的唯一地方。
杰里·本森·蒙哥马利

@Jerry我已经定义了外键。但是它仍然搜索Category_Id。您提到过针对不同版本的EF的修复程序吗?我正在使用EF 6.0我可以采用的解决方案是什么?
Ajay Aradhya

@ ajay-aradhya实际上,最初回应的人是零囚徒,他们对EF的不同版本发表了评论。
杰里·本森·蒙哥马利,

@ JerryBenson-Montgomery没关系!我做到了。是“一对一”映射导致其搜索*_ID。包括反向引用都可以。
Ajay Aradhya

1
您还可以通过添加元数据部分类来解决此问题,这样在重新生成时就不必解决此问题。 [MetadataType(typeof(MetaData))] public partial class Tour { public class MetaData { [ForeignKey(nameof(TourCategory))] public virtual TourCategory TourCategory { get; set; } } }
卡特·梅德林

40

神圣的牛-经过数小时的尝试,我终于弄明白了。

我先做EF6数据库,我想知道“范围未知列”错误-由于某种原因,它正在生成表名下划线列名,并试图查找不存在的列。

在我的情况下,我的一个表对另一个表中的同一主键有两个外键引用,如下所示:

Animals            Owners
=======            ======
AnimalID (PK)      Pet1ID    <- FK to AnimalID
                   Pet2ID    <- also FK to AnimalID

EF产生了一些奇怪的列名状Owners_AnimalID1Owners_AnimalID2,继而又打破本身。

这里的窍门是,这些混乱的外键需要使用Fluent API在EF中注册!

在主数据库上下文中,重写OnModelCreating方法并更改实体配置。最好有一个单独的文件扩展EntityConfiguration该类,但可以内联。

无论采取哪种方式,您都需要添加以下内容:

public class OwnerConfiguration : EntityTypeConfiguration<Owner>
{
    public OwnerConfiguration()
    {
        HasRequired(x => x.Animals)
            .WithMany(x => x.Owners)  // Or, just .WithMany()
            .HasForeignKey(x => x.Pet1ID);
    }
}

这样,EF将会(也许)开始按您的期望工作。繁荣。

另外,如果将上述内容与可为空的列一起使用,也会遇到相同的错误-只需使用.HasOptional()代替即可.HasRequired()


这是让我难以置信的链接:

https://social.msdn.microsoft.com/Forums/zh-CN/862abdae-b63f-45f5-8a6c-0bdd6eeabfdb/getting-sqlexception-invalid-column-name-userid-from-ef4-codeonly?forum=adonetefx

然后,Fluent API文档提供了帮助,尤其是外键示例:

http://msdn.microsoft.com/en-us/data/jj591620.aspx

您还可以将配置放在密钥的另一端,如下所述:

http://www.entityframeworktutorial.net/code-first/configure-one-to-many-relationship-in-code-first.aspx

我现在遇到了一些新问题,但是那是一个巨大的概念鸿沟,现在还没有解决。希望能帮助到你!


1
非常感谢..我有同样的问题。
萨钦·帕萨尔

这也对我builder.HasOne(item => item.LogicalShipment).WithMany(s => s.Items).HasForeignKey(item => item.LogicalShipmentId).IsRequired();
有用

14

假设:

  • Table
  • OtherTable
  • OtherTable_ID

现在选择以下方式之一:


一个)

去掉 ICollection<Table>

如果您有一些与OtherTable_ID检索时有关的错误Table,请转到OtherTable模型并确保ICollection<Table>其中没有。如果没有定义关系,则框架将自动假定您必须对OtherTable具有FK,并在生成的SQL中创建这些额外的属性。

该答案的所有功劳归@LUKE所有。上面的答案是他在@drewid答案下的评论。我认为他的评论很干净,因此我将其改写为答案。


B)

  • 添加OtherTableIdTable

  • 定义OtherTableIdTable数据库

1
这么夸张的答案!
阿米尔·侯赛因·艾哈迈迪

这个答案确实很快就得以保存。多亏了卢克,我的确读了他的评论。尽管@drewid在答案链的最后完成了它,但是它非常棒,是大多数面对这种情况所需要的。
Div Tiwari

3

就我而言,我错误地定义了由两个外键组成的主键,如下所示:

HasKey(x => x.FooId);
HasKey(x => x.BarId);

HasRequired(x => x.Foo)
    .WithMany(y => y.Foos);
HasRequired(x => x.Bar);

我得到的错误是“无效的列名Bar_ID”。

指定复合主键可以正确解决此问题:

HasKey(x => new { x.FooId, x.BarId });

...

3

对我来说,造成这种现象的原因是因为Fluent API的定义映射存在问题。我有2种相关类型,其中A型具有可选的B型对象,而B型具有许多A型对象。

public class A 
{
    
    public int? BId {get; set;}
    public B NavigationToBProperty {get; set;}
}
public class B
{
    
    public List<A> ListOfAProperty {get; set;}
}

我已经用流利的api定义了映射,如下所示:

A.HasOptional(p=> p.NavigationToBProperty).WithMany().HasForeignKey(key => key.BId);

但是问题是,类型B具有导航属性List<A>,因此我有了SQLException Invalid column name A_Id

我将Visual Studio Debug附加到EF DatabaseContext.Database.Log,以将生成的SQL输出到VS Output-> Debug窗口

db.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);

并从B表生成的SQL具有2个关系->一个具有正确的id,另一个与 A_Id

问题的原因是,我没有将此B.List<A>导航属性添加到映射中。

因此,在我的情况下,这就是正确映射的方式:

A.HasOptional(p=> p.NavigationToBProperty).WithMany(x => x.ListOfAProperty).HasForeignKey(key => key.BId);


1

我也遇到了这个问题,似乎有几个不同的原因。对我来说,它的id属性被错误地定义为int,而不是包含导航对象的父类中的long属性。数据库中的id字段被定义为bigint,它对应于C#中的long。这不会导致编译时错误,但是会导致与OP相同的运行时错误:

// Domain model parent object
public class WidgetConfig 
{
    public WidgetConfig(long id, int stateId, long? widgetId)
    {
        Id = id;
        StateId = stateId;
        WidgetId = widgetId;
    }

    private WidgetConfig()
    {
    }

    public long Id { get; set; }

    public int StateId { get; set; }

    // Ensure this type is correct
    public long? WidgetId { get; set; } 

    public virtual Widget Widget { get; set; }
}

// Domain model object
public class Widget
{
    public Widget(long id, string name, string description)
    {
        Id = id;
        Name = name;
        Description = description;
    }

    private Widget()
    {
    }

    public long Id { get; set; }

    public string Name { get; set; }

    public string Description { get; set; }
}

// EF mapping
public class WidgetConfigMap : EntityTypeConfiguration<WidgetConfig>
{
    public WidgetConfigMap()
    {
        HasKey(x => x.Id);
        ToTable(nameof(WidgetConfig));
        Property(x => x.Id).HasColumnName(nameof(WidgetConfig.Id)).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).IsRequired();
        Property(x => x.StateId).HasColumnName(nameof(WidgetConfig.StateId));
        Property(x => x.WidgetId).HasColumnName(nameof(WidgetConfig.WidgetId));
    }
}   

// Service
public class WidgetsService : ServiceBase, IWidgetsService
{
    private IWidgetsRepository _repository;

    public WidgetsService(IWidgetsRepository repository)
    {
        _repository = repository;
    }

    public List<WidgetConfig> ListWithDetails()
    {
        var list = _repository.ListWithDetails();

        return new WidgetConfigMapping().ConvertModelListToDtoList(list).ToList();
    }
}   

// Repository
public class WidgetsRepository: BaseRepository<WidgetConfig, long>, IWidgetsRepository
{
    public WidgetsRepository(Context context)
        : base(context, id => widget => widget.Id == id)
    {
    }

    public IEnumerable<WidgetConfig> ListWithDetails()
    {
        var widgets = Query
            .Include(x => x.State)
            .Include(x => x.Widget);

        return widgets;
    }
}

1

对我来说,问题是我在应用程序中两次映射了表-一次通过Code First,一次通过Database First。

就我而言,删除任何一个都可以解决问题。


1

对我而言,这是由于EF的多元化问题而发生的。对于以“ -Status”结尾的表,EF认为它的单数是“ -Statu”。将实体和数据库表名称更改为“ -StatusTypes”可修复该问题。

这样,您无需在每次更新实体模型时重命名实体模型。


0

如果您多次对同一张表进行外键引用,则可以使用InverseProperty

像这样的东西

[InverseProperty("MyID1")]
public virtual ICollection<MyTable> set1 { get; set; }
[InverseProperty("MyID2")]
public virtual ICollection<MyTable> set2 { get; set; }

0

对我来说(使用Visual Studio 2017和Entity Framework 6.1.3下的数据库优先模型),在重新启动Visual Studio和重建之后,问题消失了。


由于您没有解释原因,因此这似乎不是该问题的明确答案。它应该作为评论。
伊波(Ibo)

0

在我的情况下,我的种子方法数据仍在调用在先前迁移中已删除的表列。如果您使用的是Automapper,请仔细检查您的映射。


0

就我而言,我已经有一个数据库(数据库激发)。感谢这里的所有评论,我找到了解决方案:

这些表必须具有关系,但是列的名称必须不同,并添加ForeignKey属性。

[ForeignKey(“ PrestadorId”)]公共虚拟AwmPrestadoresServicios Colaboradores {get; 组; }

也就是说,PRE_ID是PK,但是另一个表中的FK是PRESTADOR_ID,则它可以工作。感谢这里的所有评论,我找到了解决方案。EF的工作方式很神秘。


0

如果您在同一张表上的导航属性存在此问题,则必须更改属性的名称。

例如 :

Table : PERSON
Id
AncestorId (with a foreign key which references Id named Parent) 

你必须改变AncestorIdPersonId

似乎EF试图创建一个密钥,ParentId因为它找不到名为Ancestor的表。

编辑:这是对数据库的修复!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.