我写了这样的课:
class Test { [Key] [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] public int Id { get; set; } [Required] public ListStrings { get; set; } public Test() { Strings = new List { "test", "test2", "test3", "test4" }; } }
和
internal class DataContext : DbContext { public DbSetTests { get; set; } }
运行代码后:
var db = new DataContext(); db.Tests.Add(new Test()); db.SaveChanges();
我的数据正在保存但只是保存Id
.我没有任何表格,也没有适用于字符串列表的关系.
我究竟做错了什么?我也尝试制作字符串, virtual
但它没有改变任何东西.
谢谢您的帮助.
该答案基于@Sasan和@CAD bloke提供的答案。
JsonConvert
)builder.Entity<YourEntity>().Property(p => p.Strings) .HasConversion( v => JsonConvert.SerializeObject(v), v => JsonConvert.DeserializeObject<List<string>>(v));
使用EF Core流畅配置,我们List
可以对JSON进行序列化/反序列化。
为什么此代码是您可以争取的一切的完美结合:
Sasn最初的答案的问题是,如果列表中的字符串包含逗号(或选择作为分隔符的任何字符),它将变成一个大混乱,因为它将单个条目转换为多个条目,但这是最容易阅读和阅读的。最简洁。
CAD bloke答案的问题在于它丑陋且需要更改模型,这是一种不良的设计实践(请参阅Marcell Toth对Sasan答案的评论)。但这是数据安全的唯一答案。
我知道这是一个老问题,Pawel给出了正确答案,我只想展示一个如何进行字符串处理的代码示例,并避免为基本类型列表添加额外的类.
public class Test { public Test() { _strings = new List<string> { "test", "test2", "test3", "test4" }; } [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } private List<String> _strings { get; set; } public List<string> Strings { get { return _strings; } set { _strings = value; } } [Required] public string StringsAsString { get { return String.Join(',', _strings); } set { _strings = value.Split(',').ToList(); } } }
EF Core 2.1+:
属性:
public string[] Strings { get; set; }
OnModelCreating:
modelBuilder.Entity<YourEntity>() .Property(e => e.Strings) .HasConversion( v => string.Join(',', v), v => v.Split(',', StringSplitOptions.RemoveEmptyEntries));
您将其序列化为JSON以在数据库中持久化并对其进行反序列化以重构.NET集合.这似乎比我预期的Entity Framework 6和SQLite表现更好.我知道你要求,List<string>
但这里有一个更复杂的收藏品的例子.
我标记了持久性属性,[Obsolete]
因此在正常的编码过程中对我来说非常明显"这不是你正在寻找的属性"."真实"属性被标记为,[NotMapped]
因此实体框架忽略它.
(不相关的切线):你可以用更复杂的类型做同样的事情,但你需要问自己,你是否只是为自己查询对象的属性太难了?(是的,在我的情况下).
using Newtonsoft.Json;
....
[NotMapped]
public Dictionary<string, string> MetaData { get; set; } = new Dictionary<string, string>();
/// <summary> <see cref="MetaData"/> for database persistence. </summary>
[Obsolete("Only for Persistence by EntityFramework")]
public string MetaDataJsonForDb
{
get
{
return MetaData == null || !MetaData.Any()
? null
: JsonConvert.SerializeObject(MetaData);
}
set
{
if (string.IsNullOrWhiteSpace(value))
MetaData.Clear();
else
MetaData = JsonConvert.DeserializeObject<Dictionary<string, string>>(value);
}
}
当然Pawel给出了正确的答案.但我在这篇文章中发现,自EF 6+以来,它可以保存私人财产.所以我更喜欢这段代码,因为你无法以错误的方式保存字符串.
public class Test { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } [Column] [Required] private String StringsAsStrings { get; set; } public List<String> Strings { get { return StringsAsStrings.Split(',').ToList(); } set { StringsAsStrings = String.Join(",", value); } } public Test() { Strings = new List<string> { "test", "test2", "test3", "test4" }; } }
实体框架不支持基本类型的集合.您可以创建实体(将保存到不同的表)或执行一些字符串处理以将列表保存为字符串,并在实体实现后填充列表.
只是为了简化 -
实体框架不支持原语.您可以创建一个类来包装它,也可以添加另一个属性来将列表格式化为字符串:
public ICollection<string> List { get; set; } public string ListString { get { return string.Join(",", List); } set { List = value.Split(',').ToList(); } }