C# 实体框架核心保存单个实体而不是更新
所以我一直在阅读,关于这方面的大多数问题是,你必须分离上下文,解决方案通常是创建一些外键。然而,我的问题是在一个实体上,而不是与这个实体的关系,我有外键,我可以根据需要来考虑。我认为这与使用GUID作为主键有关 我的犯罪实体是:C# 实体框架核心保存单个实体而不是更新,c#,sql,entity-framework,C#,Sql,Entity Framework,所以我一直在阅读,关于这方面的大多数问题是,你必须分离上下文,解决方案通常是创建一些外键。然而,我的问题是在一个实体上,而不是与这个实体的关系,我有外键,我可以根据需要来考虑。我认为这与使用GUID作为主键有关 我的犯罪实体是: public class Customer { public Guid Id { get; set; } public string Name { get; set; } public DateTime CreatedAt { get; set;
public class Customer
{
public Guid Id { get; set; }
public string Name { get; set; }
public DateTime CreatedAt { get; set; }
public virtual ICollection<Organization> Organizations { get; set; }
}
我用以下代码保存它:
public class AddCustomer : ICommand
{
public Guid CustomerId { get; set; }
public string Name { get; set; }
}
[Transactional]
internal sealed class HandleAddCustomer : IHandleCommand<AddCustomer>
{
private readonly IEntityWriter<Customer> _writer;
public HandleAddCustomer(IEntityWriter<Customer> writer)
{
_writer = writer;
}
public Task HandleAsync(AddCustomer command)
{
var customer = new Customer
{
Id = command.CustomerId,
Name = command.Name,
CreatedAt = DateTime.Now
};
_writer.Save(customer);
return Task.CompletedTask;
}
}
这一切都很好,很漂亮,直到我发送相同的ID
{
"CustomerId": "692da47a-3886-42bb-a1ac-d853d315109a",
"Name": "New name"
}
然后我得到一个外键冲突,因为它试图将其作为新行插入,这当然会导致一个重复的主键。所以我认为,我的罪魁祸首是处理身份证。我见过有人建议
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
但是我的主键不是由数据库生成的(来自一个现有的不相交系统),所以我只希望它与主键保持一致,并确保它是同一个实体,并且必须更新它。我需要先用一些数据查询数据库吗
if(_querys().Where(c=>c.Id==command.Id).FirstOrDefault()!=null){…//客户已经存在,更新实体中的名称并再次保存它
每次执行命令时手动检查现有实体感觉有点像意大利面条,但尽管我对EF的经验有限(尤其是EF Core),但我可能对它的期望有点过高
Edit:我一直在挖掘一位过去的员工编写的一些代码,似乎EF集成(尤其是保存)只设置实体的实际状态:
public void Save(TEntity entity)
{
var context = _contextProvider();
var entry = context.Entry(entity);
// If it is not tracked by the context, add it to the context
if (entry.State == EntityState.Detached)
{
// This also sets the entity state to added.
context.Set<TEntity>().Add(entity);
}
else
{
// Tells the context that the entity should be updated during saving changes
entry.State = EntityState.Modified;
}
}
但是关于Frederik的建议,我可能需要更新库以同时使用AddOrUpdate()偷偷编辑,这似乎还没有在EF Core.Yay中实现。是的,如果ID已经存在或不存在,您需要首先查询DB。有一个名为AddOrUpdate()的方法 您可以使用。这是一种扩展方法,您可以在此处了解更多信息:
您可能必须更改以下内容的实现:\u writer.Save(customer); 它应该是这样的:
public void Save(Customer customer)
{
var dalCustomer = context.Customers.FirstOrDefault(c => c.Id = entity.Id);
if (dalCustomer == null)
{
dalCustomer = new Customer();
context.Customers.Add(dalCustomer);
}
dalCustomer.Name = customer.Name;
dalCustomer.CreatedAt = DateTime.Now;
context.SaveChanges();
}
(此代码未经测试或编译)而不是_writer.Save(customer)在您的客户更改后,您是否尝试过使用db.SaveChanges();不幸的是,这尚未在EF Core中实现,但我认为现在的方法是创建自己的版本。
{
"CustomerId": "692da47a-3886-42bb-a1ac-d853d315109a",
"Name": "New name"
}
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public void Save(TEntity entity)
{
var context = _contextProvider();
var entry = context.Entry(entity);
// If it is not tracked by the context, add it to the context
if (entry.State == EntityState.Detached)
{
// This also sets the entity state to added.
context.Set<TEntity>().Add(entity);
}
else
{
// Tells the context that the entity should be updated during saving changes
entry.State = EntityState.Modified;
}
}
public async Task ExecuteAsync()
{
await _contextProvider().SaveChangesAsync().ConfigureAwait(false);
}
db.Customer.AddOrUpdate(customer);
public void Save(Customer customer)
{
var dalCustomer = context.Customers.FirstOrDefault(c => c.Id = entity.Id);
if (dalCustomer == null)
{
dalCustomer = new Customer();
context.Customers.Add(dalCustomer);
}
dalCustomer.Name = customer.Name;
dalCustomer.CreatedAt = DateTime.Now;
context.SaveChanges();
}