我写了这样的课:
class Test
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public List<String> Strings { get; set; }
public Test()
{
Strings = new List<string>
{
"test",
"test2",
"test3",
"test4"
};
}
}
和
internal class DataContext : DbContext
{
public DbSet<Test> Tests { get; set; }
}
运行代码后:
var db = new DataContext();
db.Tests.Add(new Test());
db.SaveChanges();
我的数据已保存,但仅保存Id
。我没有适用于字符串列表的任何表格和关系。
我做错了什么?我还尝试制作字符串 virtual
,但它没有改变任何内容。
感谢您的帮助。
答案 0 :(得分:135)
实体框架不支持基本类型的集合。您可以创建一个实体(将保存到另一个表)或执行一些字符串处理以将列表保存为字符串,并在实体实现后填充列表。
答案 1 :(得分:34)
我知道这是一个老问题,Pawel has given the correct answer,我只想展示一个如何进行字符串处理的代码示例,并避免为基本类型列表添加额外的类。
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(); }
}
}
答案 2 :(得分:27)
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));
答案 3 :(得分:21)
将序列化为JSON以保留在数据库中并对其进行反序列化以重构.NET集合。这似乎比我预期的Entity Framework 6&amp; SQLite的。我知道你要求Promise.resolve
,但这里有一个更复杂的收藏品的例子。
我用List<string>
标记了持久性属性,因此对我来说非常明显&#34;这不是您正在寻找的属性&#34;在正常的编码过程中。 &#34;真实&#34;属性标记为[Obsolete]
,因此实体框架忽略它。
(无关切线):你可以对更复杂的类型做同样的事情,但是你需要问问自己,你是否只是自己查询对象的属性太难了? (是的,就我而言)。
[NotMapped]
答案 4 :(得分:10)
只是为了简化 -
实体框架不支持基元。您可以创建一个类来包装它,也可以添加另一个属性来将列表格式化为字符串:
public ICollection<string> List { get; set; }
public string ListString
{
get { return string.Join(",", List); }
set { List = value.Split(',').ToList(); }
}
答案 5 :(得分:6)
当然Pawel has given the right answer。 但是我在这个post中发现,自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"
};
}
}
答案 6 :(得分:4)
稍微调整https://github.com/darwinex/DarwinexLabs/tree/master/tools/dwx_zeromq_connector/v2.0.1#installation的@Mathieu Viales,这是一个使用新的System.Text.Json序列化程序的.NET Standard兼容代码段,从而消除了对Newtonsoft.Json的依赖。
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.0" /> to <PackageReference Include="Microsoft.AspNetCore.App" />
请注意,尽管using System.Text.Json;
builder.Entity<YourEntity>().Property(p => p.Strings)
.HasConversion(
v => JsonSerializer.Serialize(v, default),
v => JsonSerializer.Deserialize<List<string>>(v, default));
和Serialize()
中的第二个参数通常是可选的,但会出现错误:
表达式树可能不包含使用以下内容的调用或调用 可选参数
分别将其明确设置为默认值(null)即可清除
。答案 7 :(得分:2)
您可以使用限制数组的ScalarCollection
容器并提供一些操作选项(Gist):
用法:
public class Person
{
public int Id { get; set; }
//will be stored in database as single string.
public SaclarStringCollection Phones { get; set; } = new ScalarStringCollection();
}
代码:
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
namespace System.Collections.Specialized
{
#if NET462
[ComplexType]
#endif
public abstract class ScalarCollectionBase<T> :
#if NET462
Collection<T>,
#else
ObservableCollection<T>
#endif
{
public virtual string Separator { get; } = "\n";
public virtual string ReplacementChar { get; } = " ";
public ScalarCollectionBase(params T[] values)
{
if (values != null)
foreach (var item in Items)
Items.Add(item);
}
#if NET462
[Browsable(false)]
#endif
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Not to be used directly by user, use Items property instead.")]
public string Data
{
get
{
var data = Items.Select(item => Serialize(item)
.Replace(Separator, ReplacementChar.ToString()));
return string.Join(Separator, data.Where(s => s?.Length > 0));
}
set
{
Items.Clear();
if (string.IsNullOrWhiteSpace(value))
return;
foreach (var item in value
.Split(new[] { Separator },
StringSplitOptions.RemoveEmptyEntries).Select(item => Deserialize(item)))
Items.Add(item);
}
}
public void AddRange(params T[] items)
{
if (items != null)
foreach (var item in items)
Add(item);
}
protected abstract string Serialize(T item);
protected abstract T Deserialize(string item);
}
public class ScalarStringCollection : ScalarCollectionBase<string>
{
protected override string Deserialize(string item) => item;
protected override string Serialize(string item) => item;
}
public class ScalarCollection<T> : ScalarCollectionBase<T>
where T : IConvertible
{
protected override T Deserialize(string item) =>
(T)Convert.ChangeType(item, typeof(T));
protected override string Serialize(T item) => Convert.ToString(item);
}
}
答案 8 :(得分:2)
我想补充一点,当使用Npgsql(PostgreSQL的数据提供程序)时,实际上支持原始类型的数组和列表:
答案 9 :(得分:1)
此答案基于@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或从JSON反序列化。
为什么此代码是您可以争取的所有东西的完美组合: