简体   繁体   English

实体框架7:生成无效的列名称

[英]Entity Framework 7 : Generating Invalid Column Name

using EF 7 : 1.0.0-rc1-final, 使用EF 7:1.0.0-rc1-final,

I'm having trouble with EF generating the query properly, using database first approach - using ef scaffolding to to generate some model properties listed in the DbContext - as the tables contain a large number of columns I only need a few to work for the webapi so they are column mapped 我在使用数据库第一种方法正确生成查询时遇到麻烦 - 使用ef脚手架生成DbContext中列出的一些模型属性 - 因为表包含大量列我只需要一些就能用于webapi所以它们是列映射的

I have 3 entities, Brands, Events and Sessions 我有3个实体,品牌,活动和会议

Brands contains many Events and Events contains many Sessions 品牌包含许多事件和事件包含许多会话

my models: 我的模特:

[Table("tblBranding")]
public class Brand 
{
    [Key]
    [Column("brandingId")]
    public int BrandId { get; set; }
    [Column("BrandingActive")]
    public bool Active { get; set; }
    [JsonIgnore]
    [Column("DeadBrand")]        
    public bool DeadBrand { get; set; }
    [Column("BrandingSiteTitle")]
    public string Name { get; set; }

    //navigation properties
    public virtual ICollection<Event> Events { get; set; }
}

[Table("tblEvents")]
public class Event
{           
    public int EventId { get; set; }
    [Column("eventActive")]
    public bool Active { get; set; }
    [Column("eventName")]
    public string Name { get; set; }        
    public DateTime EventCloseDate {get;set;}        
    public int PaxAllocationLimit { get; set; }

    //navigation properties             
    [JsonIgnore]        
    [Column("brandingId")]

    public virtual int BrandId { get; set; }
    [JsonIgnore]
    [ForeignKey("BrandId")]
    public virtual Brand Brand { get; set; }
    public virtual ICollection<Session> Sessions { get; set; }
}

[Table("tblEventsDates")]
public class Session
{       
    [Column("EventDateID")]
    public int SessionId { get; set; }
    [Column("EventDateName")]
    public string Name { get; set; }               
    [Column("EventDate")]
    public DateTime SessionDate { get; set; }        
    [Column("EventDateTime")]
    public DateTime SessionTime { get; set; }
    [Column("EventDateMinutes")]
    public decimal? SessionDurationInMinutes { get; set; }
    [Column("EventDateArrival")]
    public DateTime? ArrivalTime { get; set; }
    [Column("EventCapacity")]
    public int SessionCapacity { get; set; }

    //navigation properties        
    [JsonIgnore]        
    public virtual int EventId { get; set; }
    [JsonIgnore]        
    public virtual Event Event { get; set; }            
}

My DbContext 我的DbContext

protected override void OnModelCreating(ModelBuilder modelBuilder) 
{       
    modelBuilder.Entity<Event>()
        .HasOne(e => e.Brand)
        .WithMany(b => b.Events).HasForeignKey(e=>e.BrandId);

    modelBuilder.Entity<Event>()
        .HasMany(s => s.Sessions)
        .WithOne(e => e.Event).HasForeignKey(s => s.EventId);

    modelBuilder.Entity<Event>(entity=> {
        entity.Property(e => e.EventId).HasColumnName("EventID");
        entity.HasKey(e => new{ e.EventId, e.EventCloseDate});
        entity.HasIndex(e => e.EventId).HasName("For Full Text Indexing").IsUnique();
        entity.Property(e => e.Active).HasDefaultValue(false);
        entity.Property(e => e.EventCloseDate)
            .HasColumnType("datetime")
            .HasDefaultValueSql("'1/1/2038'");
        entity.Property(e => e.Name).HasMaxLength(1024);
        entity.Property(e => e.PaxAllocationLimit).HasDefaultValue(10000);
    });

    modelBuilder.Entity<Brand>(entity => {
        entity.HasKey(e => e.BrandId);                

        entity.Property(e => e.Active).HasDefaultValue(false);               

        entity.Property(e => e.Name)
            .IsRequired()
            .HasMaxLength(150)
            .HasColumnType("varchar");                
    });

    modelBuilder.Entity<Session>(entity => {
        entity.HasKey(e => e.SessionId);

        entity.Property(e=>e.Name)
          .HasMaxLength(250)
            .HasColumnType("varchar")
            .HasDefaultValue("");

        entity.Property(e => e.SessionDurationInMinutes)
            .HasColumnType("numeric")
            .HasDefaultValue(0m);                
        });
    }

    public virtual DbSet<Brand> Brands { get; set; }
    public virtual DbSet<Event> Events { get; set; }        
    public virtual DbSet<Session> Sessions { get; set; }
}

I'm using the project as a webapi, when I call up Brands, it generates the following SQL: 我正在使用该项目作为webapi,当我调用Brands时,它会生成以下SQL:

SELECT [e].[brandingId], [e].[BrandingActive], [e].[DeadBrand], [e].[BrandingSiteTitle]
FROM [tblBranding] AS [e]
WHERE [e].[BrandingActive] = 1
ORDER BY [e].[BrandingSiteTitle], [e].[brandingId]
Microsoft.Data.Entity.Storage.Internal.RelationalCommandBuilderFactory: Information: Executed DbCommand (75ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT [t].[EventId], [t].[EventCloseDate], [t].[eventActive], [t].[brandingId], [t].[EventId1], [t].[eventName], [t].[PaxAllocationLimit]
FROM [tblEvents] AS [t]
INNER JOIN (
    SELECT DISTINCT [e].[BrandingSiteTitle], [e].[brandingId]
    FROM [tblBranding] AS [e]
    WHERE [e].[BrandingActive] = 1
) AS [e] ON [t].[brandingId] = [e].[brandingId]
ORDER BY [e].[BrandingSiteTitle], [e].[brandingId]

where [t].[EventId1] column name is invalid note that If I comment out the following code in DbContext - this error goes away and the query is generated correctly: 其中[t]。[EventId1]列名无效请注意,如果我在DbContext中注释掉以下代码 - 此错误消失并且查询生成正确:

modelBuilder.Entity<Event>()
            .HasMany(s => s.Sessions)
            .WithOne(e => e.Event).HasForeignKey(s => s.EventId);

I have tried adding [ForeignKey], [InverseProperty] attributes while 'fiddling' - it doesn't seem to make a difference 我试过添加[ForeignKey],[InverseProperty]属性而'摆弄' - 它似乎没有什么区别

I also tried adding the column name explicitly as mentioned here 提到我也尝试添加列名明确这里

I'm not sure what else to try - it starts happening only when I define the relationship to Sessions in FluidUI - suggestions ? 我不确定还有什么可以尝试 - 只有当我在FluidUI中定义与Sessions的关系时才开始发生 - 建议?

Just for fun. 纯娱乐。 try making this database. 尝试制作这个数据库。 I removed a lot of the "clutter" EF is like ASP.NET MVC based on the concept of convention over configuration. 我删除了很多“杂乱”的EF就像ASP.NET MVC一样,基于约定优于配置的概念。

You have done the configuration up to 2 times (attributes and/or FluentApi) , while in reality you could have done it 0 times. 您最多完成了2次配置(属性和/或FluentApi),而实际上您可以完成0次。

Here are some base rules on convention (conventions are not case sensitive to trigger). 以下是约定的一些基本规则(约定对触发器不区分大小写)。

  • To make a Key (aka primary key) you must name it either Id or [classname]Id 要创建密钥(也称为主密钥),您必须将其命名为Id或[classname] Id
  • To make a foreign key you name it [foreighClassName(partA)]Id (you dont need this if you add the next instead (and ofc you can have both at the same time but then the name must be the same (partA) 要创建一个外键,你可以将它命名为[foreighClassName(partA)] Id(如果你添加下一个,你不需要这个(而且你可以同时添加两个,但是名称必须相同)(partA)
  • To access the foreign "body" object, you just add a property of the type like this public Brand Brand { get; set; } 要访问外部“body”对象,只需添加类似此public Brand Brand { get; set; } public Brand Brand { get; set; } public Brand Brand { get; set; } , the name is not important if there is only one "link". public Brand Brand { get; set; } ,如果只有一个“链接”,名称并不重要。
  • On the primary side you might want to use some sort of collection to wrap all the children, and yes public ICollection<Event> Events { get; set; } 在初级端,您可能希望使用某种集合来包装所有子public ICollection<Event> Events { get; set; } ,并且是public ICollection<Event> Events { get; set; } public ICollection<Event> Events { get; set; } public ICollection<Event> Events { get; set; } is the way to go. public ICollection<Event> Events { get; set; }是要走的路。 One might ask what about IEnumerable or IList (well think of it this way, IEnumerable cannot do .Add() so it is more or less read only. IList well it does all and more, and would be a nice fit if it where not for it doing stuff that's untranslatable to SQL. so in the middle we have ICollection . 有人可能会问IEnumerableIList是什么(好好想想这样, IEnumerable不能这样做.Add()所以它或多或少是只读的IList很好,它会做得越来越多,如果它不在哪里就会很合适因为它做的东西是不可翻译的SQL。所以在中间我们有ICollection

When you use the virtual keyword? 当您使用虚拟关键字时? Well in EF7 you don't use it, as its for enabling lazy loading, and EF7 don't have that (yet) and we don't know if they are to add it. 好吧在EF7中你不使用它,因为它用于启用延迟加载,而EF7没有(还),我们不知道它们是否要添加它。 Github EF7 feature request lacking lazyload Github EF7功能请求缺乏延迟

Why did I remove [JsonIgnore] attributes? 为什么我删除[JsonIgnore]属性? NEVER send the entity models to the client. 切勿将实体模型发送给客户端。 Create a proper DTO (popularly called a model in ASP.NET MVC) 创建一个合适的DTO(在ASP.NET MVC中通常称为模型)

Remember to do Migration, and (for fun) try first without any "hardcoded" requirements in the FluentAPI and look at the mig code you will see PK/FK are done, Indexes and several other bobs and pins are added for you. 记得做迁移,并且(为了好玩)首先尝试在FluentAPI中没有任何“硬编码”要求,看看你会看到PK / FK完成的迁移代码,为你添加索引和其他几个bob和别针。

public class Brand 
{
    public int Id { get; set; }
    public bool Active { get; set; }
    public bool DeadBrand { get; set; }
    public string Name { get; set; }

    //navigation properties
    public ICollection<Event> Events { get; set; }
}

public class Event
{           
    public int Id { get; set; }
    public bool Active { get; set; }
    public string Name { get; set; }        
    public DateTime EventCloseDate {get;set;}        
    public int PaxAllocationLimit { get; set; }

    //navigation properties             
    public Brand Brand { get; set; }
    public ICollection<Session> Sessions { get; set; }
}

public class Session
{       
    public int Id { get; set; }
    public string Name { get; set; }   
    //Datetime contains date and time        
    public DateTime Time { get; set; } 
    //TimeSpan is for duration, allowing access to seconds, minutes, hours etc.
    public TimeSpan Duration { get; set; } 
    public DateTime? ArrivalTime { get; set; }
    public int SessionCapacity { get; set; }

    //navigation properties        
    public Event Event { get; set; }            
}

Context class 上下文类

class DbContex{

    public virtual DbSet<Brand> Brands { get; set; }
    public virtual DbSet<Event> Events { get; set; }        
    public virtual DbSet<Session> Sessions { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder) 
    {       
    //Personally I would not have many requirements in the database unless I              
    //was completely sure it had to be that way.
    //They will ALWAYS bite you in the ass in the long run.

        modelBuilder.Entity<Event>(entity=> {
            entity.Property(e => e.Active).HasDefaultValue(false);
            entity.Property(e => e.EventCloseDate)
                .HasColumnType("datetime")
                .HasDefaultValueSql("'1/1/2038'");
            entity.Property(e => e.Name).HasMaxLength(1024);
            entity.Property(e => e.PaxAllocationLimit).HasDefaultValue(10000);
        });

        modelBuilder.Entity<Brand>(entity => {
            entity.Property(e => e.Active).HasDefaultValue(false);    
            entity.Property(e => e.Name)
                .IsRequired()
                .HasMaxLength(150)
                .HasColumnType("varchar");                
        });

        modelBuilder.Entity<Session>(entity => {
            entity.Property(e=>e.Name)
                .HasMaxLength(250)
                .HasColumnType("varchar")
                .HasDefaultValue("");    
            entity.Property(e => e.SessionDurationInMinutes)
                .HasColumnType("numeric")
                .HasDefaultValue(0m);                
            });
        }
    }
}

Answering my own question - it seems like it might be a bug in EF 7 1.0.0-RC1 回答我自己的问题 - 好像它可能是EF 7 1.0.0-RC1中的一个错误

in the entity properties for Event in DbContext 在DbContext中的Event的实体属性中

 modelBuilder.Entity<Event>(entity=> {
    entity.Property(e => e.EventId).HasColumnName("EventID");
    entity.HasKey(e => new{ e.EventId, e.EventCloseDate});
    entity.HasIndex(e => e.EventId).HasName("For Full Text Indexing").IsUnique();
    entity.Property(e => e.Active).HasDefaultValue(false);
    entity.Property(e => e.EventCloseDate)
        .HasColumnType("datetime")
        .HasDefaultValueSql("'1/1/2038'");
    entity.Property(e => e.Name).HasMaxLength(1024);
    entity.Property(e => e.PaxAllocationLimit).HasDefaultValue(10000);
});

Note that it has 2 keys - which was generated from scaffolding, the table has a composite primary key 请注意,它有2个键 - 从脚手架生成,表有一个复合主键

However for my requirements with the API I only need a primary identifier - removing the composite key fixed the invalid column generation error 但是,对于我对API的要求,我只需要一个主标识符 - 删除复合键修复了无效列生成错误

updated code: 更新的代码:

modelBuilder.Entity<Event>(entity=> {
    entity.Property(e => e.EventId).HasColumnName("EventID");
    entity.HasKey(e => e.EventId);
    entity.HasIndex(e => e.EventId).HasName("For Full Text Indexing").IsUnique();
    entity.Property(e => e.Active).HasDefaultValue(false);
    entity.Property(e => e.EventCloseDate)
        .HasColumnType("datetime")
        .HasDefaultValueSql("'1/1/2038'");
    entity.Property(e => e.Name).HasMaxLength(1024);
    entity.Property(e => e.PaxAllocationLimit).HasDefaultValue(10000);
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM