Entity Framework – Código primero – No se puede almacenar la lista

Escribí tal clase:

class Test { [Key] [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] public int Id { get; set; } [Required] public List Strings { get; set; } public Test() { Strings = new List { "test", "test2", "test3", "test4" }; } } 

y

 internal class DataContext : DbContext { public DbSet Tests { get; set; } } 

Después de ejecutar el código:

 var db = new DataContext(); db.Tests.Add(new Test()); db.SaveChanges(); 

mis datos se están guardando, pero solo el Id . No tengo tablas ni relaciones que se apliquen a la lista de cadenas .

¿Qué estoy haciendo mal? Intenté también hacer cadenas virtual pero no cambié nada.

Gracias por tu ayuda.

Entity Framework no admite colecciones de tipos primitivos. Puede crear una entidad (que se guardará en una tabla diferente) o realizar un procesamiento de cadenas para guardar su lista como una cadena y completar la lista una vez que la entidad se haya materializado.

Sé que esta es una pregunta antigua, y Pawel me ha dado la respuesta correcta , solo quería mostrar un ejemplo de código de cómo hacer un procesamiento de cadenas y evitar una clase adicional para la lista de un tipo primitivo.

 public class Test { public Test() { _strings = new List { "test", "test2", "test3", "test4" }; } [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } private List _strings { get; set; } public List Strings { get { return _strings; } set { _strings = value; } } [Required] public string StringsAsString { get { return String.Join(',', _strings); } set { _strings = value.Split(',').ToList(); } } } 

JSON.NET al rescate.

Lo serializa en JSON para que persista en la base de datos y lo deserialice para reconstituir la colección .NET. Esto parece funcionar mejor de lo que esperaba con Entity Framework 6 y SQLite. Sé que solicitó List pero aquí hay un ejemplo de una colección aún más compleja que funciona bien.

Etiqueté la propiedad persistente con [Obsolete] por lo que sería muy obvio para mí que “esta no es la propiedad que está buscando” en el curso normal de la encoding. La propiedad “real” está etiquetada con [NotMapped] por lo que Entity framework lo ignora.

(tangente no relacionada): podría hacer lo mismo con tipos más complejos, pero debe preguntarse ¿acaso usted hizo que las propiedades de ese objeto fueran demasiado difíciles para usted? (sí, en mi caso).

 using Newtonsoft.Json; .... [NotMapped] public Dictionary MetaData { get; set; } = new Dictionary(); ///   for database persistence.  [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>(value); } } 

Solo para simplificar –

El marco de la entidad no admite primitivas. Puede crear una clase para ajustarla o agregar otra propiedad para formatear la lista como una cadena:

 public ICollection List { get; set; } public string ListString { get { return string.Join(",", List); } set { List = value.Split(',').ToList(); } } 

Por supuesto, Pawel ha dado la respuesta correcta . Pero encontré en esta publicación que desde EF 6+ es posible guardar propiedades privadas. Así que preferiría este código, porque no puede guardar las cadenas de una manera incorrecta.

 public class Test { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } [Column] [Required] private String StringsAsStrings { get; set; } public List Strings { get { return StringsAsStrings.Split(',').ToList(); } set { StringsAsStrings = String.Join(",", value); } } public Test() { Strings = new List { "test", "test2", "test3", "test4" }; } } 

Puede usar este contenedor ScalarCollection que limita una matriz y proporciona algunas opciones de manipulación ( Gist ):

Uso:

 public class Person { public int Id { get; set; } //will be stored in database as single string. public SaclarStringCollection Phones { get; set; } = new ScalarStringCollection(); } 

Código:

 using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; namespace System.Collections.Specialized { #if NET462 [ComplexType] #endif public abstract class ScalarCollectionBase : #if NET462 Collection, #else ObservableCollection #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 { protected override string Deserialize(string item) => item; protected override string Serialize(string item) => item; } public class ScalarCollection : ScalarCollectionBase where T : IConvertible { protected override T Deserialize(string item) => (T)Convert.ChangeType(item, typeof(T)); protected override string Serialize(T item) => Convert.ToString(item); } }