如何在实体框架代码优先数据库中手动设置实体主键

本文关键字:实体 设置 数据库 框架 代码 | 更新日期: 2023-09-27 17:58:01

好吧,我有以下模型结构:我有一个类-DatabaseEntity,它基本上是

public class DatabaseEntity
{
    public int Id { get; set; }
}

因此,产品、类别等每个实体都将继承DatabaseEntity并具有Id属性。此外,我有一个典型的EntityFramework存储库类,使用InsertOrUpdate方法:

private readonly DbContext _database;
public void InsertOrUpdate<TObject>(TObject entity) where TObject : DatabaseEntity
{
    if(entity.Id == default(int))
    {
         // New entity
         DbSet<TObject>().Add(entity);
    }
    else
    {
         // Existing entity
         _database.Entry(entity).State = EntityState.Modified;
    }
    _database.SaveChanges();
}

然后我通过易趣api从易趣上下载我必须添加到数据库中的类别列表。基本类别是:

public class EbayCategory : DatabaseEntity
{
    // It has Id since it inherits DatabaseEntity
    public string Name { get; set; }      
    // ... some other properties
}

但是,问题是,当我下载这些类别时,我会下载它们的Id属性,当然,这些属性已经有了值。当我试图将它们保存到数据库时,比如:

public void UpdateCategories(IEnumerable<EbayCategory> newCategories)
{
    foreach (var newCategory in newCategories)
    {
        _repository.InsertOrUpdate(newCategory);
    }
}

我面临一些问题。。。首先,entity.Id != default(int)因为它有值,所以存储库尝试更新这个实体,而不是添加,但它不在数据库或上下文中,所以它抛出以下异常:

System.Data.Entity.Infrastructure.DbUpdateConcurencyException
"Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries."

因为它认为其他人删除了我正在尝试更新的实体。我如何保存这个InsertOrUpdate逻辑,因为很多项目都是基于它的,并且能够向数据库中添加带有主键(Id)的项(EbayCategories),然后像其他实体一样更新/删除它们,而不丢弃EbayCategory.Id值?

如何在实体框架代码优先数据库中手动设置实体主键

要允许您手动生成ID,您需要一个具有手动生成ID的类,因此它不能从DatabaseEntity 继承

public class EbayCategory
{
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int Id { get; set; }
    public string Name { get; set; }      
    // ... some other properties
}

现在,您将需要一个不同的InsertOrUpdate来处理具有手动生成密钥的实体:

public void InsertOrUpdate(EbayCategory entity)
{
    if(Find(entity.ID == null)
    {
         // New entity
         DbSet<EbayCategory>().Add(entity);
    }
    else
    {
         // Existing entity
         _database.Entry(entity).State = EntityState.Modified;
    }
    _database.SaveChanges();
}

Colin上面的回答非常正确地展示了如何使用数据注释实现此设置。但在所提出的问题中,实体是一个子类,因此在不更改实体类的情况下无法添加注释。

还有一种可供选择的配置方法:Fluent configuration。下面是我使用EntityTypeConfiguration类的示例:

public class LookupSchoolsConfiguration : EntityTypeConfiguration<LookupSchools>
    {
        public LookupSchoolsConfiguration()
        {
            Property(l => l.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
        }
    }

您也可以根据以下帖子将配置直接添加到modelBuilder中:https://stackoverflow.com/a/4999894/486028