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 유창한 구성을 사용하여 ListJSON으로 /에서 직렬화 / 역 직렬화합니다 .
이 코드가 노력할 수있는 모든 것의 완벽한 조합 인 이유 :
- 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 |