如何使用Entity Framework Core将属性设置为“Identity”或自动递增列?

时间:2018-05-21 00:53:21

标签: c# wpf entity-framework entity-framework-core

在我使用c#编写的新WPF项目中,我想尝试使用Entity Framework Core与我的SQL Server数据库进行交互。

每当我尝试将模型添加到我的上下文时,我都会收到以下错误

  

当IDENTITY_INSERT设置为OFF时,无法在表'Orders'中为identity列插入显式值。

我正在使用RepositoryUnitOfWork来封装Entity Framework Core方法来执行所需的工作。

但最简单的是,我正在执行以下代码

var order = new Order();
order.Title = "some";
....
Context.Orders.Add(order);
Context.SaveChanges();

这是我的模特

public class Order
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Int64 Id { get; set; }

    public string Status { get; set; }
    public int? CustomerId { get; set; }
    public DateTime? Birthdate { get; set; }
    public int UtcOffset { get; set; }\
    public DateTime CreatedAt { get; set; }
    public DateTime? UpdatedAt { get; set; }
    public int? UpdatedBy { get; set; }

    [ForeignKey(nameof(Creator))]
    public int CreatedBy { get; set; }

    public Order()
    {
        CreatedAt = DateTime.UtcNow;
    }

    public virtual User Creator { get; set; }
    public virtual Customer Customer { get; set; }
}

可能导致此问题的原因是什么?

更新

以下是我的表格创建方式

CREATE TABLE [dbo].[Orders](
    [Id] [bigint] IDENTITY(1,1) NOT NULL,
    [Status] [varchar](50) NOT NULL,
    [CustomerId] [int] NULL,
    [Birthdate] [datetime] NULL,
    [CreatedBy] [int] NOT NULL,
    [CreatedAt] [datetime] NOT NULL,
    [UpdatedBy] [int] NULL,
    [UpdatedAt] [datetime] NULL,
    [UtcOffset] [int] NOT NULL,
 CONSTRAINT [PK_Orders] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

以下是创建Order模型

的方法
public Order Create(int? customerId, DateTime? birthdate)
{
    var order = new Order();
    order.CustomerId = customerId;
    order.Birthdate = birthdate;
    order.Status = OrderStatus.Sold.ToString();
    order.CreatedBy = Passport.Identity.Id;

    var updatedOrder = Orders.Add(order);
    Orders.Save();

    return updatedOrder;
}

这是我的存储库实现

public class EntityRepository<TEntity, TKeyType> : IRepository<TEntity, TKeyType>
    where TEntity : class
    where TKeyType : struct
{
    protected readonly DbContext Context;
    protected readonly DbSet<TEntity> DbSet;

    public EntityRepository(DbContext context)
    {
        Context = context;
        DbSet = context.Set<TEntity>();
    }

    public TEntity Get(TKeyType id)
    {
        return DbSet.Find(id);
    }

    public IEnumerable<TEntity> GetAll()
    {
        return DbSet.ToList();
    }

    public bool Any(Expression<Func<TEntity, bool>> predicate)
    {
        return DbSet.Any(predicate);
    }

    public IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
    {
        return DbSet.Where(predicate);
    }

    public TEntity SingleOrDefault(Expression<Func<TEntity, bool>> predicate)
    {
        return DbSet.SingleOrDefault(predicate);
    }

    public virtual TEntity Add(TEntity entity)
    {
        DbSet.Add(entity);

        return entity;
    }

    public virtual IEnumerable<TEntity> AddRange(IEnumerable<TEntity> entities)
    {
        DbSet.AddRange(entities);

        return entities;
    }

    public void Remove(TEntity entity)
    {
        DbSet.Remove(entity);
    }

    public void RemoveRange(IEnumerable<TEntity> entities)
    {
        DbSet.RemoveRange(entities);
    }

    public void Update(TEntity entity)
    {
        DbSet.Attach(entity);
        var record = Context.Entry(entity);
        record.State = EntityState.Modified;
    }

    public IQueryable<TEntity> Query()
    {
        return DbSet;
    }

    public void Save()
    {
        Context.SaveChanges();
    }
}

public class EntityRepository<TEntity> : EntityRepository<TEntity, int>
   where TEntity : class
{
    public EntityRepository(DbContext context)
        : base(context)
    {
    }
}

此外,这个问题在Entity Framework error: Cannot insert explicit value for identity column in table上并不重复,因为我正在使用[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]装饰我的Id属性。此外,我使用数据库第一种方法,所以我使用MSSMS手动创建了我的数据库

2 个答案:

答案 0 :(得分:4)

此问题可能是以下两种情况之一

首先,您可能会无意中使用自动映射工具设置Id属性。如果您使用自AutoMapperValueInjecterOoMapper等自动映射实用程序,请确保在目标对象为{{1}时将映射配置为忽略Id属性模型。例如,使用AutoMapper,使用以下语法将auto-mapper配置为Order属性的任何值。

Id

第二种情况,您所看到的内容可能与EntityFrameworkCore Bug有关。而不是使用数据注释(即expression.CreateMap<OrderViewModel, Order>() .ForMember(src => src.Id, opts => opts.Ignore()); ),尝试使用流利的上下文类的[DatabaseGenerated(DatabaseGeneratedOption.Identity)]将id属性定义为身份

OnModelCreating

如果这确实是你的问题,上面的代码也应解决第一个场景。上面的行protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // Here we identify the Id property to be set to Identity // Also, we use change the PropertySaveBehavior on the same // property to ignore the values modelBuilder.Entity(modelType) .Property(key.Name) .UseSqlServerIdentityColumn() .Metadata.BeforeSaveBehavior = PropertySaveBehavior.Ignore; } 告诉EntityCore不要在insert语句中包含Metadata.BeforeSaveBehavior = PropertySaveBehavior.Ignore;列。因此,即使您映射器将映射值映射到Id属性,也会从insert语句中排除错误映射值的值。

此外,您可以使用反射来设置&#34; Id&#34;所有数据集上的属性使您的工作流程更加强大,或者如果您有许多数据库集,则您不必一次添加一个数据集。以下是如何使用反射配置模型以生成名为Id标识的列的示例。

Id

答案 1 :(得分:0)

就我而言,我必须将entity.Property(e => e.TranId).ValueGeneratedOnAdd();添加到上下文文件中。

modelBuilder.Entity<PersonalTrades>(entity =>
{
     entity.Property(e => e.TranId).ValueGeneratedOnAdd();
}

我没有从Automapper更新身份字段(TranId)。最终,上面的更改对我起作用了,正如名称所示,它在插入记录时为标识字段生成了值。