Entity Framework-코드 우선-목록을 저장할 수 없음
나는 그런 수업을 썼다.
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
. 문자열 목록에 적용되는 테이블이나 관계가 없습니다 .
내가 도대체 뭘 잘못하고있는 겁니까? 나는 또한 Strings 를 만들려고 시도했지만 virtual
아무것도 변경하지 않았습니다.
도와 주셔서 감사합니다.
Entity Framework는 기본 형식 컬렉션을 지원하지 않습니다. 엔티티 (다른 테이블에 저장 됨)를 생성하거나 일부 문자열 처리를 수행하여 목록을 문자열로 저장하고 엔티티가 구체화 된 후 목록을 채울 수 있습니다.
나는 이것이 오래된 질문이라는 것을 알고 있으며 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 .
JSON으로 직렬화하여 데이터베이스에 유지하고 역 직렬화하여 .NET 컬렉션을 재구성합니다. 이것은 Entity Framework 6 및 SQLite에서 예상했던 것보다 더 잘 수행되는 것 같습니다. 나는 당신이 요청한 것을 알고 List<string>
있지만 여기에 잘 작동하는 훨씬 더 복잡한 컬렉션의 예가 있습니다.
지속 형 속성에 태그를 지정 [Obsolete]
했으므로 정상적인 코딩 과정에서 "이것은 당신이 찾고있는 속성이 아닙니다"라는 것이 매우 분명 할 것입니다. "real"속성에는 태그가 지정 [NotMapped]
되므로 Entity 프레임 워크는이를 무시합니다.
(관련되지 않은 탄젠트) : 더 복잡한 유형으로 동일한 작업을 수행 할 수 있지만 해당 객체의 속성을 쿼리하기가 너무 어렵게 만들었습니까? (예, 제 경우에는).
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);
}
}
이 답변은 @Sasan 및 @CAD bloke가 제공 한 답변을 기반으로합니다 .
EF Core 2.1 이상에서만 작동 (.NET Standard와 호환되지 않음) (Newtonsoft 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 블로크의 답변의 문제점은보기 흉하고 모델을 변경해야한다는 것입니다. 이는 잘못된 설계 관행입니다 ( Sasan의 답변 에 대한 Marcell Toth의 의견 참조 ). 그러나 데이터에 안전한 유일한 대답입니다.
단순화하기 위해-
엔티티 프레임 워크는 프리미티브를 지원하지 않습니다. 래핑 할 클래스를 만들거나 다른 속성을 추가하여 목록을 문자열로 형식화합니다.
public ICollection<string> List { get; set; }
public string ListString
{
get { return string.Join(",", List); }
set { List = value.Split(',').ToList(); }
}
물론 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"
};
}
}
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);
}
}
참고 URL : https://stackoverflow.com/questions/20711986/entity-framework-code-first-cant-store-liststring
'code' 카테고리의 다른 글
TextInputLayout을 사용할 때 @ id / visible 리소스를 확인할 수 없습니다. (0) | 2020.10.06 |
---|---|
Android-브로드 캐스트 수신기 onReceive ()에서 컨텍스트 가져 오기 (0) | 2020.10.06 |
정수를 특정 범위로 고정하는 방법은 무엇입니까? (0) | 2020.10.06 |
500.21 모듈 목록에 잘못된 모듈“ManagedPipelineHandler”가 있습니다. (0) | 2020.10.06 |
NSArray를 NSData로 변환하는 방법? (0) | 2020.10.06 |