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团队博客文章或者只是试验(试验和错误,你知道)。 –

相关问题