0

我正在重構複雜類型類的工作實現來應用值對象模式,這將使它成爲一個不可變的類型。EFCF 6複雜類型映射失敗後重構值對象模式

我得到了那個工作,我曾想過,直到我嘗試爲這些更改設置遷移(我認爲EF的主要變化是,我將某些屬性更改爲僅獲取它們以前的位置有setter)。我目前收到以下錯誤,當我運行Update-數據庫:

PM> update-database 
Specify the '-Verbose' flag to view the SQL statements being applied to the target database. 
Applying explicit migrations: [201701010745393_initial]. 
Applying explicit migration: 201701010745393_initial. 
Running Seed method. 
System.Data.Entity.Core.EntityCommandCompilationException: An error occurred while preparing the command definition. See the inner exception for details. ---> System.Data.Entity.Core.MappingException: 
(29,10) : error 3004: Problem in mapping fragments starting at line 29:No mapping specified for properties Contact.Address in Set Contacts. 

(46,10) : error 3004: Problem in mapping fragments starting at line 46:No mapping specified for properties Company.Address in Set Companies. 

(56,10) : error 3004: Problem in mapping fragments starting at line 56:No mapping specified for properties CompanyLocation.Address in Set Locations. 

這似乎可以無視我一直在閱讀有關EF如何處理複雜類型,因爲每當遇到實體應該自動映射的東西它使用了一個複雜類型的屬性。這是以前的情況,但它是不再適用於不可變類的更改。我不知道這是爲什麼。

下面是有關這些錯誤信息有關的類:

public class Company : PocoBase 
{ 
    [Required] 
    public Address Address { get; set; } 

    public virtual ICollection<Client> Clients { get; set; } 

    public virtual ICollection<CompanyLocation> Locations { get; set; } 

    [Required] 
    public string Name { get; set; } 
} 

public class CompanyLocation : PocoBase 
{ 
    [Required] 
    public Address Address { get; set; } 

    public virtual Company Company { get; set; } 

    [ForeignKey("Company")] 
    public Guid CompanyId { get; set; } 

    public string Description { get; set; } 

    public string Label { get; set; } 
} 

public class Contact : PocoBase 
{ 
    public Address Address { get; set; } 

    [Required] 
    public string CellNumber { get; set; } 

    public virtual Client Client { get; set; } 

    [ForeignKey("Client")] 
    public Guid ClientId { get; set; } 

    public virtual Company Company { get; set; } 

    [ForeignKey("Company")] 
    public Guid CompanyId { get; set; } 

    [Required] 
    public string Email { get; set; } 

    [Required] 
    public string Name { get; set; } 

    [Required] 
    public string OfficeNumber { get; set; } 
} 

,當然,所有重要的Address類,這是現在造成的問題!

[ComplexType] 
public class Address 
{ 
    [Required] 
    public string City { get; } 

    [Required] 
    public string Country { get; } 

    [Required, StringLength(10, MinimumLength = 5)] 
    public string PostalCode { get; } 

    [Required, StringLength(2, MinimumLength = 2)] 
    public string State { get; } 

    [Required] 
    public string StreetAddress { get; } 

    public string UnitNumber { get; } 

    public Address(string street, string city, string state, string zip, string unit = null) : this("United States", street, city, state, zip, unit) { } 

    public Address(string country, string street, string city, string state, string zip, string unit = null) 
    { 
     VerifyZipCodeFormat(zip); 

     Country = country; 
     StreetAddress = street; 
     City = city; 
     State = state; 
     PostalCode = zip; 
     UnitNumber = unit; 
    } 

    private static void VerifyZipCodeFormat(string zip) 
    { 
     if (zip.Length > 5) 
      if (zip[5] != '-') 
       throw new ArgumentOutOfRangeException(nameof(zip), zip[5], "Postal Code must be in the format of \"XXXXX\" or \"XXXXX-XXXX\""); 
      else if (zip.Length != 10) 
       throw new ArgumentOutOfRangeException(nameof(zip), zip.Length, "Postal Code must be either 5 or 10 characters, in either the format of \"XXXXX\" or \"XXXXX-XXXX\""); 
    } 

    public Address WithCity(string city) 
    { 
     return new Address(Country, StreetAddress, city, State, PostalCode, UnitNumber); 
    } 
    public Address WithCountry(string country) 
    { 
     return new Address(country, StreetAddress, City, State, PostalCode, UnitNumber); 
    } 
    public Address WithStateOrProvince(string state) 
    { 
     return new Address(Country, StreetAddress, City, state, PostalCode, UnitNumber); 
    } 
    public Address WithStreetAddress(string street) 
    { 
     return new Address(Country, street, City, State, PostalCode, UnitNumber); 
    } 
    public Address WithUnitNumber(string unit) 
    { 
     return new Address(Country, StreetAddress, City, State, PostalCode, unit); 
    } 
    public Address WithZipOrPostalCode(string zip) 
    { 
     VerifyZipCodeFormat(zip); 

     return new Address(Country, StreetAddress, City, State, zip, UnitNumber); 
    } 
} 

我試圖手動執行此映射,我相信EFCF公約是同樣 - Address_PropertyName在遷移文件EF不會嘗試創建,當我運行添加遷移,但這並沒有工作。

既沒有[ComplexTypeAttribute]也沒有使用modelBuilder.ComplexType()行解決了這些錯誤消息,所以我必須假定它與現在是一個不可變類有關。

我曾希望添加列名稱的[ColumnAttribute]會以某種方式解決問題,因爲這似乎表明this post,但是這也沒有解決問題。

回答

2

既沒有[ComplexTypeAttribute]也沒有使用modelBuilder.ComplexType()行來解決這些錯誤消息,所以我必須假設它與現在是不可變類有關。

這是正確的。 EF6沒有映射獲取唯一屬性,並且沒有辦法通過數據註釋或流暢配置(注意EF Core中的行爲不同,但是still causes issues)改變該行爲,因此提供私人設置者將解決問題:

[ComplexType] // optional 
public class Address 
{ 
    [Required] 
    public string City { get; private set; } 

    [Required] 
    public string Country { get; private set; } 

    [Required, StringLength(10, MinimumLength = 5)] 
    public string PostalCode { get; private set; } 

    [Required, StringLength(2, MinimumLength = 2)] 
    public string State { get; private set; } 

    [Required] 
    public string StreetAddress { get; private set; } 

    public string UnitNumber { get; private set; } 

    // ... 
} 

現在,我知道這不等同於確保字段僅在施工期間設置的原始實施。但總的來說,我建議你在建模EF實體時忘記面向對象的原則,模式和實踐。實體類基本上是代表數據庫表,記錄和關係的DTO,沒有關聯的業務邏輯。另請注意,EF使用引用標識跟蹤實體,因此在實體類型上應用不可變原則只會導致問題(幸運的是,不適用於複雜類型)。

+0

謝謝你提供的信息,伊萬。你知道微軟表示這是一個地方嗎?我不確定在將來如何看待這種情況 - 在提出這個問題之前,谷歌搜索並沒有什麼幫助。 –

+1

嗨克里斯,不幸的沒有。EF信息主要來自一些EF團隊博客文章或者只是試驗(試驗和錯誤,你知道)。 –

相關問題