2017-03-01 115 views
0

所以我一直在閱讀,似乎大多數問題是你必須不相交的上下文,並且解決方案似乎通常創建一些外鍵。然而,我的問題是在一個單一的實體上,而不是與這個實體的關係,而且我可以根據需要想到外鍵。我認爲它與使用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中實現。好極了。

+0

相反_writer.Save(客戶)的你有沒有試着用db.SaveChanges();客戶變更後? –

回答

0

有()

db.Customer.AddOrUpdate(customer); 

那你可以使用一個叫做AddOrUpdate的方法。這是一個擴展方法,您可以在這裏瞭解更多信息: https://msdn.microsoft.com/en-us/library/hh846520(v=vs.103).aspx

+0

不幸的是,這在EF內核中尚未實現,但我認爲現在的方法是爲我創建自己的版本。 – Dennis

0

是的,如果ID已經存在或不存在,您需要先查詢數據庫。

0

您可能必須更改以下內容的實現:_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(); 
} 

(此代碼是沒有測試或編譯)