entity framework选项来映射string列表或int列表(List <string>)

我想用EF来存储一个包含基本列表的对象。

public class MyObject { public int Id {get;set;} public virtual IList<int> Numbers {get;set;} } 

我知道EF不能存储这个,但我想知道可能的解决scheme来解决这个问题。

我能想到的两个解决scheme是:

1. 创build一个具有Id和Integervalue 的Dummy对象 ,例如

 public class MyObject { public int Id {get;set;} public virtual IList<MyInt> Numbers {get;set;} } public class MyInt { public int Id {get;set;} public int Number {get;set;} } 

2. 将列表值存储为blob ,例如

 public class MyObject { public int Id {get;set;} /// use NumbersValue to persist/load the list values public string NumbersValue {get;set;} [NotMapped] public virtual IList<int> Numbers { get { return NumbersValue.split(','); } set { NumbersValue = value.ToArray().Join(","); } } } 

2.方法的问题是,我必须创build一个自定义IList实现来跟踪是否有人修改了返回的集合。

有没有更好的解决scheme呢?

虽然我不喜欢回答我自己的问题,但是这里解决了我的问题:

当我发现这个关于复杂types的链接后,我尝试了几个实现,并在一些头痛之后,我结束了这一点。

List值直接存储为表中的string,所以不需要执行多个连接来获取列表条目。 实现者只需要将每个列表项的对话实现为一个持久化string(参见代码示例)。

大部分代码都是在Baseclass(PersistableScalarCollection)中处理的。 你只需要从它的每个数据types(int,string等等)派生出来,并实现方法来序列化/反序列化这个值。

重要的是要注意, 你不能直接使用generics基类 (当你删除摘要的时候)。 EF似乎无法正常工作。 您还必须确保使用[ComplexType]属性注释派生类。

另外请注意,似乎不可能为IList<T>实现ComplexType,因为EF抱怨Indexer(因此我继续进行ICollection)。

同样值得注意的是,由于所有内容都存储在一列中, 因此无法search集合中的值(至less在数据库中)。 在这种情况下,您可以跳过这个实现或者将数据非规范化以进行search。

整数集合示例:

  /// <summary> /// ALlows persisting of a simple integer collection. /// </summary> [ComplexType] public class PersistableIntCollection : PersistableScalarCollection<int> { protected override int ConvertSingleValueToRuntime(string rawValue) { return int.Parse(rawValue); } protected override string ConvertSingleValueToPersistable(int value) { return value.ToString(); } } 

用法示例:

 public class MyObject { public int Id {get;set;} public virtual PersistableIntCollection Numbers {get;set;} } 

这是通过将列表条目存储在string中来处理持久性方面的基类:

  /// <summary> /// Baseclass that allows persisting of scalar values as a collection (which is not supported by EF 4.3) /// </summary> /// <typeparam name="T">Type of the single collection entry that should be persisted.</typeparam> [ComplexType] public abstract class PersistableScalarCollection<T> : ICollection<T> { // use a character that will not occur in the collection. // this can be overriden using the given abstract methods (eg for list of strings). const string DefaultValueSeperator = "|"; readonly string[] DefaultValueSeperators = new string[] { DefaultValueSeperator }; /// <summary> /// The internal data container for the list data. /// </summary> private List<T> Data { get; set; } public PersistableScalarCollection() { Data = new List<T>(); } /// <summary> /// Implementors have to convert the given value raw value to the correct runtime-type. /// </summary> /// <param name="rawValue">the already seperated raw value from the database</param> /// <returns></returns> protected abstract T ConvertSingleValueToRuntime(string rawValue); /// <summary> /// Implementors should convert the given runtime value to a persistable form. /// </summary> /// <param name="value"></param> /// <returns></returns> protected abstract string ConvertSingleValueToPersistable(T value); /// <summary> /// Deriving classes can override the string that is used to seperate single values /// </summary> protected virtual string ValueSeperator { get { return DefaultValueSeperator; } } /// <summary> /// Deriving classes can override the string that is used to seperate single values /// </summary> protected virtual string[] ValueSeperators { get { return DefaultValueSeperators; } } /// <summary> /// DO NOT Modeify manually! This is only used to store/load the data. /// </summary> public string SerializedValue { get { var serializedValue = string.Join(ValueSeperator.ToString(), Data.Select(x => ConvertSingleValueToPersistable(x)) .ToArray()); return serializedValue; } set { Data.Clear(); if (string.IsNullOrEmpty(value)) { return; } Data = new List<T>(value.Split(ValueSeperators, StringSplitOptions.None) .Select(x => ConvertSingleValueToRuntime(x))); } } #region ICollection<T> Members public void Add(T item) { Data.Add(item); } public void Clear() { Data.Clear(); } public bool Contains(T item) { return Data.Contains(item); } public void CopyTo(T[] array, int arrayIndex) { Data.CopyTo(array, arrayIndex); } public int Count { get { return Data.Count; } } public bool IsReadOnly { get { return false; } } public bool Remove(T item) { return Data.Remove(item); } #endregion #region IEnumerable<T> Members public IEnumerator<T> GetEnumerator() { return Data.GetEnumerator(); } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return Data.GetEnumerator(); } #endregion }