实体框架选项映射列表的列表或列表(列表< string>) [英] Entity Framework options to map list of strings or list of int (List<string>)

查看:115
本文介绍了实体框架选项映射列表的列表或列表(列表< string>)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用EF存储包含原始列表的对象。

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

我知道,

这个,但是我想知道可能的解决方案来解决这个问题。



我可以想到的2个解决方案是:



1. 创建一个具有Id和Integervalue的虚拟对象,例如

  public class MyObject {
public int Id {get; set;}
public virtual IList&MyInt>数字{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;}

///使用NumbersValue来保存/加载列表值
public string NumbersValue {get; set;}

[NotMapped]
public virtual IList< int> Numbers {
get {
return NumbersValue.split(',');
}
set {
NumbersValue = value.ToArray()。Join(,);
}
}
}

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



是否有更好的解决方案>?

解决方案

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



当我发现关于 复杂类型 我尝试了几个实现,一些头痛之后,我结束了这个。



List值被存储为一个字符串该表直接,所以不需要执行几个连接才能获得列表条目。实现者只需将每个列表条目的会话实现为持久性字符串(参见代码示例)。



大多数代码在Baseclass(PersistableScalarCollection)中处理。您只需从每个数据类型(int,string等)派生它,并实现方法来序列化/反序列化该值。



重要的是要注意,你不能直接使用通用的baseclass (当你删除摘要)。看来,EF无法正常工作。您还必须确保使用 [ComplexType] 属性对派生类进行注释。



另请注意似乎不可能为 IList< T> 实现ComplexType,因为EF抱怨Indexer(因此我继续使用ICollection)。还需要注意的是,由于所有内容都存储在一列中,因此无法在集合中搜索中的值(至少在数据库中) )。在这种情况下,您可以跳过此实现或反向归一化数据进行搜索。



整数集合的示例:

  ///< summary> 
///延续一个简单的整数集合。
///< / 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;}
}

这是通过将列表条目存储在字符串中来处理持久性方面的baseclass: / p>

  ///< summary> 
///允许将标量值作为集合(不受EF 4.3支持)的Baseclass
///< / summary>
///< typeparam name =T>应该保留的单个集合条目的类型。< / typeparam>
[ComplexType]
public abstract class PersistableScalarCollection< T> :ICollection< T> {

//使用不会在集合中发生的字符。
//这可以使用给定的抽象方法(例如,用于列表列表)进行覆盖。
const string DefaultValueSeperator =|;

readonly string [] DefaultValueSeperators = new string [] {DefaultValueSeperator};

///< summary>
///列表数据的内部数据容器。
///< / summary>
私人列表< T>数据{get;组; }

public PersistableScalarCollection(){
Data = new List< T>();
}

///< summary>
///实现者必须将给定的值原始值转换为正确的运行时类型。
///< / summary>
///< param name =rawValue>数据库中已分离的原始值< / param>
///< returns>< / returns>
protected abstract T ConvertSingleValueToRuntime(string rawValue);

///< summary>
///实现者应该将给定的运行时值转换为持久化的形式。
///< / summary>
///< param name =value>< / param>
///< returns>< / returns>
protected abstract string ConvertSingleValueToPersistable(T value);

///< summary>
///派生类可以覆盖用于分隔单个值的字符串
///< / summary>
保护虚拟字符串ValueSeperator {
get {
return DefaultValueSeperator;
}
}

///< summary>
///派生类可以覆盖用于分隔单个值的字符串
///< / summary>
protected virtual string [] ValueSperators {
get {
return DefaultValueSeperators;
}
}

///< summary>
///不要手动模式化!这仅用于存储/加载数据。
///< / 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>会员

public void Add(T item){
Data.Add(item);
}

public void Clear(){
Data.Clear();
}

public bool包含(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>成员

public IEnumerator< T> GetEnumerator(){
return Data.GetEnumerator();
}

#endregion

#region IEnumerable成员

IEnumerator IEnumerable.GetEnumerator(){
return Data.GetEnumerator ();
}

#endregion
}


I want to store an object that contains a List of primitives using EF.

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

I know that EF cannot store this, but I'd like to know possible solutions to solve this problem.

The 2 Solutions I can think of are:

1.Create a Dummy object that has an Id and the Integervalue, e.g.

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.Store the list values as a blob, e.g.

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(",");
         }
    }
}

The Problem with the 2. approach is, that I have to create a Custom IList implementation to keep track if someone modifies the returned collection.

Is there a better solution for this?

解决方案

Although I do not like to answer my own question, but here is what solved my problem:

After I found this link about Complex Types I tried several implementations, and after some headache I ended up with this.

The List values get stored as a string on the table directly, so it's not required to perform several joins in order to get the list entries. Implementors only have to implement the conversation for each list entry to a persistable string (see the Code example).

Most of the code is handled in the Baseclass (PersistableScalarCollection). You only have to derive from it per datatype (int, string, etc) and implement the method to serialize/deserialize the value.

It's important to note, that you cannot use the the generic baseclass directly (when you remove the abstract). It seems that EF cannot work with that. You also have to make sure to annotate the derived class with the [ComplexType] attribute.

Also note that it seems not to be possible to implement a ComplexType for IList<T> because EF complains about the Indexer (therefore I went on with ICollection).

It's also important to note, that since everything is stored within one column, you cannot search for values in the Collection (at least on the database). In this case you may skip this implementation or denormalize the data for searching.

Example for a Collection of integers:

    /// <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();
        }
    }

Usage example:

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

This is the baseclass that handles the persistence aspect by storing the list entries within a 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 (e.g. 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
    }

这篇关于实体框架选项映射列表的列表或列表(列表&lt; string&gt;)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆