将自定义对象列表映射为 Entity Framework 中的 json
Map custom list of object as json in Entity Framework
我正在练习 DDD,我有一个 class,也就是所谓的 ValueObject
。在 Entity
中,我有那个 ValueObject
的自定义列表。我试图将该集合保存为 JSON.
我有以下 classes:
public class User : Entity
{
public string Username {get;set;}
private string _phoneNumbers = string.Empty;
public virtual PhoneList PhoneNumbers
{
get => (PhoneList)_phoneNumbers;
set => _phoneNumbers = value;
}
}
// A class to map the IList of PhoneNumber to string and vice versa
public class PhoneList : IEnumerable<PhoneNumber>
{
private IList<PhoneNumber> PhoneNumbers{ get; }
public PhoneList(IList<PhoneNumber> phoneNumbers)
{
PhoneNumbers = phoneNumbers;
}
public static explicit operator PhoneList(string phoneList)
{
var phoneNumbers = JsonConvert.DeserializeObject<IList<PhoneNumber>>(phoneList);
return new PhoneList(phoneNumbers);
}
public static implicit operator string(PhoneList phoneList)
{
return JsonConvert.SerializeObject(phoneList);
}
public IEnumerator<PhoneNumber> GetEnumerator()
{
return PhoneNumbers.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class PhoneNumber : ValueObject
{
public string Number {get;set;}
protected override IEnumerable<object> GetAtomicValues()
{
yield return Number;
}
}
当我 运行 使用命令的 EF Core 迁移工具时:Add-Migration InitialCreate
然后我得到以下错误:
Error: The entity type 'PhoneNumber' requires a primary key to be defined.
重点是我不想给 PhoneNumber
添加主键,因为它是 ValueObject
.
我也不明白为什么会在迁移中抛出错误。
我该如何解决这个问题?
PS。我从 this site
得到这个想法
迁移引发错误,因为 EF 正在尝试映射您的 属性 User.PhoneNumbers
。您必须告诉 EF 忽略 属性 并映射您的字符串字段 User._phoneNumbers
.
为此,您可以使用注释或流利的 API。检查 this page 以获取两者的示例。
流利API:
class MyDbContext : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.Ignore(u => u.PhoneNumbers) //Do not map property
.Property("_phoneNumbers"); //Map field
...
}
}
如果 PhoneNumbers
和 _phoneNumbers
的数据类型相同,您无需执行任何操作,因为 EF 会隐式处理私有字段作为 [=42] 的支持字段=] 属性 基于命名约定,但这不是你的情况,因为数据类型不同。有关 EF here.
中支持字段的更多信息
正因为如此,您在尝试映射 _phoneNumbers
字段时也可能会出错,因为已经有一个名为 PhoneNumbers
的 属性 但它没有预期的字符串类型。在这种情况下,您应该重命名您的字段或 属性 以确保它们不遵循支持字段命名约定(一个不是另一个带有“_”前缀的驼峰版本)。
通过明确忽略 属性 你的错误应该消失了。 EF 仅映射在 DbContext
中具有 DbSet
的实体、在其他映射实体的导航属性中使用的实体,或包含在 OnModelCreating
方法中的实体。无论如何,如果您仍然遇到 ValueObject
实体的迁移错误,您可以在 OnModelCreating
:
中明确忽略这些实体
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//Do not map these entities
modelBuilder.Ignore<PhoneNumber>();
modelBuilder.Ignore<PhoneList>();
...
}
有关 EF 如何根据约定决定要映射哪些实体的更多信息 here。
The whole point is that I don't want to add a primary key to PhoneNumber, because it's a ValueObject.
PhoneNumber
确实是 Value object
但仅在域层的上下文中。从 Persistence 的角度来看,PhoneNumber
可能 是 Entity
,这并不违背 DDD。如果您将其视为 Value object
,那么您正在遵循 DDD 方法。持久性是另一种与其他武器战斗的野兽。
我所说的是基于 Vaughn Vernon "Implementing DDD" 的书。这是相关章节的一段话:
There are times, however, when a Value Object in the model will of
necessity be stored as an Entity with respect to a relational
persistence store. In other words, when persisted, an instance of a
specific Value Object type will occupy its own row in a relational
database table that exists specifically for its type, and it will have
its own database primary key column. This happens, for example, when
supporting a collection of Value Object instances with ORM. In such
cases the Value type persistent data is modeled as a database entity.
我正在练习 DDD,我有一个 class,也就是所谓的 ValueObject
。在 Entity
中,我有那个 ValueObject
的自定义列表。我试图将该集合保存为 JSON.
我有以下 classes:
public class User : Entity
{
public string Username {get;set;}
private string _phoneNumbers = string.Empty;
public virtual PhoneList PhoneNumbers
{
get => (PhoneList)_phoneNumbers;
set => _phoneNumbers = value;
}
}
// A class to map the IList of PhoneNumber to string and vice versa
public class PhoneList : IEnumerable<PhoneNumber>
{
private IList<PhoneNumber> PhoneNumbers{ get; }
public PhoneList(IList<PhoneNumber> phoneNumbers)
{
PhoneNumbers = phoneNumbers;
}
public static explicit operator PhoneList(string phoneList)
{
var phoneNumbers = JsonConvert.DeserializeObject<IList<PhoneNumber>>(phoneList);
return new PhoneList(phoneNumbers);
}
public static implicit operator string(PhoneList phoneList)
{
return JsonConvert.SerializeObject(phoneList);
}
public IEnumerator<PhoneNumber> GetEnumerator()
{
return PhoneNumbers.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class PhoneNumber : ValueObject
{
public string Number {get;set;}
protected override IEnumerable<object> GetAtomicValues()
{
yield return Number;
}
}
当我 运行 使用命令的 EF Core 迁移工具时:Add-Migration InitialCreate
然后我得到以下错误:
Error: The entity type 'PhoneNumber' requires a primary key to be defined.
重点是我不想给 PhoneNumber
添加主键,因为它是 ValueObject
.
我也不明白为什么会在迁移中抛出错误。
我该如何解决这个问题?
PS。我从 this site
得到这个想法迁移引发错误,因为 EF 正在尝试映射您的 属性 User.PhoneNumbers
。您必须告诉 EF 忽略 属性 并映射您的字符串字段 User._phoneNumbers
.
为此,您可以使用注释或流利的 API。检查 this page 以获取两者的示例。
流利API:
class MyDbContext : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.Ignore(u => u.PhoneNumbers) //Do not map property
.Property("_phoneNumbers"); //Map field
...
}
}
如果 PhoneNumbers
和 _phoneNumbers
的数据类型相同,您无需执行任何操作,因为 EF 会隐式处理私有字段作为 [=42] 的支持字段=] 属性 基于命名约定,但这不是你的情况,因为数据类型不同。有关 EF here.
正因为如此,您在尝试映射 _phoneNumbers
字段时也可能会出错,因为已经有一个名为 PhoneNumbers
的 属性 但它没有预期的字符串类型。在这种情况下,您应该重命名您的字段或 属性 以确保它们不遵循支持字段命名约定(一个不是另一个带有“_”前缀的驼峰版本)。
通过明确忽略 属性 你的错误应该消失了。 EF 仅映射在 DbContext
中具有 DbSet
的实体、在其他映射实体的导航属性中使用的实体,或包含在 OnModelCreating
方法中的实体。无论如何,如果您仍然遇到 ValueObject
实体的迁移错误,您可以在 OnModelCreating
:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//Do not map these entities
modelBuilder.Ignore<PhoneNumber>();
modelBuilder.Ignore<PhoneList>();
...
}
有关 EF 如何根据约定决定要映射哪些实体的更多信息 here。
The whole point is that I don't want to add a primary key to PhoneNumber, because it's a ValueObject.
PhoneNumber
确实是 Value object
但仅在域层的上下文中。从 Persistence 的角度来看,PhoneNumber
可能 是 Entity
,这并不违背 DDD。如果您将其视为 Value object
,那么您正在遵循 DDD 方法。持久性是另一种与其他武器战斗的野兽。
我所说的是基于 Vaughn Vernon "Implementing DDD" 的书。这是相关章节的一段话:
There are times, however, when a Value Object in the model will of necessity be stored as an Entity with respect to a relational persistence store. In other words, when persisted, an instance of a specific Value Object type will occupy its own row in a relational database table that exists specifically for its type, and it will have its own database primary key column. This happens, for example, when supporting a collection of Value Object instances with ORM. In such cases the Value type persistent data is modeled as a database entity.