所以我一直在閱讀,似乎大多數問題是你必須不相交的上下文,並且解決方案似乎通常創建一些外鍵。然而,我的問題是在一個單一的實體上,而不是與這個實體的關係,而且我可以根據需要想到外鍵。我認爲它與使用GUID作爲主鍵有關。實體框架核心保存單個實體而不是更新
我犯罪的實體是:
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; }
}
已配置了一口流利的API如下:
public override void Configure(EntityTypeBuilder<Customer> entity)
{
entity.HasKey(customer => customer.Id); // Primary key
entity.Property(customer => customer.Name).IsRequired().HasMaxLength(255);
entity.Property(customer => customer.CreatedAt).IsRequired();
entity.HasMany(customer => customer.Organizations)
.WithOne(organization => organization.Customer)
.HasForeignKey(organization => organization.CustomerId);
}
生成下面的SQL:
CREATE TABLE [Customer] (
[Id] uniqueidentifier NOT NULL,
[CreatedAt] datetime2 NOT NULL,
[Name] nvarchar(255) NOT NULL,
CONSTRAINT [PK_Customer] PRIMARY KEY ([Id])
);
我救它與此代碼:
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;
}
}
entityWriter是我們爲更加均勻地處理數據庫交互而創建的系統,它是一個支持實體框架的包裝器,並用SimpleInjector和DI包裝它。
參數命令populatedfrom的API端點:
[HttpPost("AddCustomer")]
public async Task<IActionResult> AddCustomer(AddCustomer customer)
{
await _commands.ExecuteAsync(customer);
return Ok("Customer Saved");
}
通過以下有效載荷:
{
"CustomerId": "692da47a-3886-42bb-a1ac-d853d315109a",
"Name": "Test Customer"
}
所有工作正常,花花公子,直到我發送相同的ID。
{
"CustomerId": "692da47a-3886-42bb-a1ac-d853d315109a",
"Name": "New name"
}
然後我得到了一個外鍵衝突,因爲它試圖將它插入新行,從而導致過程的重複的主鍵。所以我認爲,我的罪魁禍首是處理Id。我見過的人建議
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
但不是由數據庫(來自現有的脫節系統)產生我的主鍵,所以我只是希望它堅持主鍵,看看它的同一個實體它必須更新它。我需要一些
if(_queries<Customer>().Where(c => c.Id == command.Id).FirstOrDefault() != null) { ...//The customer already exists, update the name in the entity and save it again
它只是感覺有點意大利麪條codeish爲現有的實體每次我執行命令時手動檢查首先查詢數據庫,但儘管我與EF的經驗是有限的(尤其是EF Core),它可能只是我對它的期望太高了。
編輯:我已經挖通過過去的員工寫了一些代碼,它似乎是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;
}
}
而且然後工作單元處理與SaveChangesAsync():
public async Task ExecuteAsync()
{
await _contextProvider().SaveChangesAsync().ConfigureAwait(false);
}
但隨着關於弗雷德裏克的建議,我可能需要更新圖書館也使用AddOrUpdate()偷偷摸摸編輯這似乎還沒有在EF Core中實現。好極了。
相反_writer.Save(客戶)的你有沒有試着用db.SaveChanges();客戶變更後? –