Entity Framework 核心接收 0 作为 Id 作为播种,尽管我将其定义为其他内容
Entity Framework Core receiving 0 for seeding as Id although I defined it to be something else
尝试添加迁移时,ef core 出现以下错误:
The seed entity for entity type 'MyEntity' cannot be added because a
non-zero value is required for property 'Id'. Consider providing a
negative value to avoid collisions with non-seed data.
实体 MyEntity 及其 superclass/interface:
public class MyEntity: EntityObject
{
public long OrderId { get; set; }
public List<StateChange> StateChanges { get; set; }
}
public class EntityObject : IEntityObject
{
[Key]
public int Id { get; set; }
[Timestamp]
public byte[] RowVersion
{
get;
set;
}
}
public class IEntityObject
{
int Id { get; set;
byte[] RowVersion { get; set; }
}
播种:
var seed = new MyEntity{ Id = -2, StateChanges = new List<StateChange>(), OrderId = -2 };
modelBuilder.Entity<MyEntity>().HasData(seed);
我一直在尝试使用 [Key] 和 [DatabaseGenerated] 进行各种操作,但找不到解决方案。
所有 ef core nuget 依赖项的版本都是 3.1.5
将classIEntityObject
更改为接口。
这是一个完全可用的控制台项目,它假定 StateChange
是您的一些内部 class 而不是 model/entity class:
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace IssueConsoleTemplate
{
public interface IEntityObject // <-- changed from `class` to `interface`
{
int Id { get; set; }
byte[] RowVersion { get; set; }
}
public class EntityObject : IEntityObject
{
[Key]
public int Id { get; set; }
[Timestamp]
public byte[] RowVersion
{
get;
set;
}
}
public class MyEntity : EntityObject
{
public long OrderId { get; set; }
public List<StateChange> StateChanges { get; set; }
}
public class StateChange
{
}
public class Context : DbContext
{
public DbSet<MyEntity> MyEntities { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(@"Data Source=.\MSSQL14;Integrated Security=SSPI;Initial Catalog=So62865284")
.UseLoggerFactory(
LoggerFactory.Create(
b => b
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MyEntity>(
entity =>
{
entity.Ignore(e => e.StateChanges); // <-- ignore your internal class
entity.HasData(
new MyEntity
{
Id = 2,
StateChanges = new List<StateChange>(),
OrderId = 2
});
});
}
}
internal static class Program
{
private static void Main()
{
using var context = new Context();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var myEntitiesWithStateChanges = context.MyEntities
.OrderBy(i => i.Id)
.ToList();
Debug.Assert(myEntitiesWithStateChanges.Count == 1);
}
}
}
如果 StateChange
也应该是一个模型 class/entity,那么您应该向它添加一个外键并设置关系。这可能看起来像这样:
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace IssueConsoleTemplate
{
public interface IEntityObject // <-- changed from `class` to `interface`
{
int Id { get; set; }
byte[] RowVersion { get; set; }
}
public class EntityObject : IEntityObject
{
[Key]
public int Id { get; set; }
[Timestamp]
public byte[] RowVersion
{
get;
set;
}
}
public class MyEntity : EntityObject
{
public long OrderId { get; set; }
public List<StateChange> StateChanges { get; set; } = new List<StateChanges>();
}
public class StateChange : EntityObject
{
public int MyEntityId { get; set; } // <-- added FK
public MyEntity MyEntity { get; set; } // <-- added navigation property
}
public class Context : DbContext
{
public DbSet<MyEntity> MyEntities { get; set; }
public DbSet<StateChange> StateChanges { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(@"Data Source=.\MSSQL14;Integrated Security=SSPI;Initial Catalog=So62865284")
.UseLoggerFactory(
LoggerFactory.Create(
b => b
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MyEntity>(
entity =>
{
// Added the relationship definition (not really necessary here,
// because this would also work by convention).
entity.HasMany(e => e.StateChanges)
.WithOne(s => s.MyEntity)
.HasForeignKey(s => s.MyEntityId);
entity.HasData(
new MyEntity
{
Id = 2,
OrderId = 2
});
});
modelBuilder.Entity<StateChange>(
entity =>
{
entity.HasData(
new StateChange
{
Id = 2,
MyEntityId = 2,
});
});
}
}
internal static class Program
{
private static void Main()
{
using var context = new Context();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var myEntitiesWithStateChanges = context.MyEntities
.Include(e => e.StateChanges)
.OrderBy(i => i.Id)
.ToList();
Debug.Assert(myEntitiesWithStateChanges.Count == 1);
Debug.Assert(myEntitiesWithStateChanges[0].StateChanges.Count == 1);
}
}
}
我同意lauxjpn 提供的答案。加上我的两分钱来解释为什么会这样。
当实体之间定义了关系时,'HasData' 方法不适用于实体。请注意 'HasData' 接收的参数等同于在 table.
中创建的列
因此,根据所讨论的实体设计,为 MyEntity
对象创建的 table 将不包含 StateChange
实体关系数据。事实上,StateChange
实体将有一个 MyEntityId
列来引用外键形式的 Entity
对象 ID。
为了添加种子数据,您必须通过使用匿名类型(在实体属性和 table 列不匹配)基于生成的 table 列。
modelBuilder.Entity<MyEntity>().HasData(
new
{
Id = 1,
OrderId = 2,
});
modelBuilder.Entity<StateChange>().HasData(
new
{
MyEntityId = 1,
//Fill in remaining properties of State Change
});
有关使用 'HasData' 进行数据播种的更多信息,请访问 Microsoft 文档网站。
尝试添加迁移时,ef core 出现以下错误:
The seed entity for entity type 'MyEntity' cannot be added because a non-zero value is required for property 'Id'. Consider providing a negative value to avoid collisions with non-seed data.
实体 MyEntity 及其 superclass/interface:
public class MyEntity: EntityObject
{
public long OrderId { get; set; }
public List<StateChange> StateChanges { get; set; }
}
public class EntityObject : IEntityObject
{
[Key]
public int Id { get; set; }
[Timestamp]
public byte[] RowVersion
{
get;
set;
}
}
public class IEntityObject
{
int Id { get; set;
byte[] RowVersion { get; set; }
}
播种:
var seed = new MyEntity{ Id = -2, StateChanges = new List<StateChange>(), OrderId = -2 };
modelBuilder.Entity<MyEntity>().HasData(seed);
我一直在尝试使用 [Key] 和 [DatabaseGenerated] 进行各种操作,但找不到解决方案。 所有 ef core nuget 依赖项的版本都是 3.1.5
将classIEntityObject
更改为接口。
这是一个完全可用的控制台项目,它假定 StateChange
是您的一些内部 class 而不是 model/entity class:
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace IssueConsoleTemplate
{
public interface IEntityObject // <-- changed from `class` to `interface`
{
int Id { get; set; }
byte[] RowVersion { get; set; }
}
public class EntityObject : IEntityObject
{
[Key]
public int Id { get; set; }
[Timestamp]
public byte[] RowVersion
{
get;
set;
}
}
public class MyEntity : EntityObject
{
public long OrderId { get; set; }
public List<StateChange> StateChanges { get; set; }
}
public class StateChange
{
}
public class Context : DbContext
{
public DbSet<MyEntity> MyEntities { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(@"Data Source=.\MSSQL14;Integrated Security=SSPI;Initial Catalog=So62865284")
.UseLoggerFactory(
LoggerFactory.Create(
b => b
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MyEntity>(
entity =>
{
entity.Ignore(e => e.StateChanges); // <-- ignore your internal class
entity.HasData(
new MyEntity
{
Id = 2,
StateChanges = new List<StateChange>(),
OrderId = 2
});
});
}
}
internal static class Program
{
private static void Main()
{
using var context = new Context();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var myEntitiesWithStateChanges = context.MyEntities
.OrderBy(i => i.Id)
.ToList();
Debug.Assert(myEntitiesWithStateChanges.Count == 1);
}
}
}
如果 StateChange
也应该是一个模型 class/entity,那么您应该向它添加一个外键并设置关系。这可能看起来像这样:
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace IssueConsoleTemplate
{
public interface IEntityObject // <-- changed from `class` to `interface`
{
int Id { get; set; }
byte[] RowVersion { get; set; }
}
public class EntityObject : IEntityObject
{
[Key]
public int Id { get; set; }
[Timestamp]
public byte[] RowVersion
{
get;
set;
}
}
public class MyEntity : EntityObject
{
public long OrderId { get; set; }
public List<StateChange> StateChanges { get; set; } = new List<StateChanges>();
}
public class StateChange : EntityObject
{
public int MyEntityId { get; set; } // <-- added FK
public MyEntity MyEntity { get; set; } // <-- added navigation property
}
public class Context : DbContext
{
public DbSet<MyEntity> MyEntities { get; set; }
public DbSet<StateChange> StateChanges { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(@"Data Source=.\MSSQL14;Integrated Security=SSPI;Initial Catalog=So62865284")
.UseLoggerFactory(
LoggerFactory.Create(
b => b
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MyEntity>(
entity =>
{
// Added the relationship definition (not really necessary here,
// because this would also work by convention).
entity.HasMany(e => e.StateChanges)
.WithOne(s => s.MyEntity)
.HasForeignKey(s => s.MyEntityId);
entity.HasData(
new MyEntity
{
Id = 2,
OrderId = 2
});
});
modelBuilder.Entity<StateChange>(
entity =>
{
entity.HasData(
new StateChange
{
Id = 2,
MyEntityId = 2,
});
});
}
}
internal static class Program
{
private static void Main()
{
using var context = new Context();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var myEntitiesWithStateChanges = context.MyEntities
.Include(e => e.StateChanges)
.OrderBy(i => i.Id)
.ToList();
Debug.Assert(myEntitiesWithStateChanges.Count == 1);
Debug.Assert(myEntitiesWithStateChanges[0].StateChanges.Count == 1);
}
}
}
我同意lauxjpn 提供的答案。加上我的两分钱来解释为什么会这样。
当实体之间定义了关系时,'HasData' 方法不适用于实体。请注意 'HasData' 接收的参数等同于在 table.
中创建的列因此,根据所讨论的实体设计,为 MyEntity
对象创建的 table 将不包含 StateChange
实体关系数据。事实上,StateChange
实体将有一个 MyEntityId
列来引用外键形式的 Entity
对象 ID。
为了添加种子数据,您必须通过使用匿名类型(在实体属性和 table 列不匹配)基于生成的 table 列。
modelBuilder.Entity<MyEntity>().HasData(
new
{
Id = 1,
OrderId = 2,
});
modelBuilder.Entity<StateChange>().HasData(
new
{
MyEntityId = 1,
//Fill in remaining properties of State Change
});
有关使用 'HasData' 进行数据播种的更多信息,请访问 Microsoft 文档网站。