繁体   English   中英

在实体框架代码第一种方法中映射字典

[英]Map a Dictionary in Entity Framework Code First Approach

我有一个这样的字典:

/// <summary>
/// Gets the leave entitlement details.
/// </summary>
/// <value>The leave entitlement details.</value>
public Dictionary<string, EmployeeLeaveEntitlement> LeaveEntitlementDetails { get; set; }  

我想将它映射到数据库。 是否可以使用受保护或私有List <>? 如:

/// <summary>
/// Gets the leave entitlement details.
/// </summary>
/// <value>The leave entitlement details.</value>
public Dictionary<string, EmployeeLeaveEntitlement> LeaveEntitlementDetails { get; set; } 

public List<EmployeeLeaveEntitlement> LeveEntitlementStore
{
    get
    {
        List<EmployeeLeaveEntitlement> leaveEntitlements = new List<EmployeeLeaveEntitlement>();

        foreach (KeyValuePair<string, EmployeeLeaveEntitlement> leaveType in LeaveEntitlementDetails)
        {
            leaveEntitlements.Add(leaveType.Value);
        }

        return leaveEntitlements;
    }
    set
    {
        foreach (EmployeeLeaveEntitlement item in value)
        {
            this.LeaveEntitlementDetails.Add(item.LeaveType, item);
        }
    }
}

谁能帮我?

在DB中使用XML列

所以今天我遇到了同样的问题,在考虑之后我找到了一个很酷的解决方案,即使我迟到了,也想与社区分享。 基本上我已经创建了一个包装系统,它将Dictionary的数据作为XML Column保存到Database中,所以稍后我也可以根据需要从数据库中查询XML。

亲这种方法

  • 使用方便
  • 快速实施
  • 你可以使用字典
  • 您可以查询XML列

首先,这是我所有模特的骨头:

public abstract class BaseEntity 
{
    /// <summary>
    /// ID of the model
    /// </summary>
    public int ID { get; set; }
}

假设我有一个包含Dictionary<string,string>和一个String属性,该属性包含在XML序列化和反序列化字典的逻辑,如下面的代码片段所示:

public class MyCoolModel : Base.BaseEntity
{
    /// <summary>
    /// Contains XML data of the attributes
    /// </summary>
    public string AttributesData
    {
        get
        {
            var xElem = new XElement(
                "items",
                Attributes.Select(x => new XElement("item", new XAttribute("key", x.Key), new XAttribute("value", x.Value)))
             );
            return xElem.ToString();
        }
        set
        {
            var xElem = XElement.Parse(value);
            var dict = xElem.Descendants("item")
                                .ToDictionary(
                                    x => (string)x.Attribute("key"), 
                                    x => (string)x.Attribute("value"));
            Attributes = dict;
        }
    }

    //Some other stuff

    /// <summary>
    /// Some cool description
    /// </summary>
    [NotMapped]
    public Dictionary<string, string> Attributes { get; set; }
}

然后我实现了一个BaseMapping类,它从EntityTypeConfiguration<T>继承

class BaseMapping<TEntity> : EntityTypeConfiguration<TEntity>
    where TEntity : Model.Base.BaseEntity
{
    public BaseMapping()
    {
        //Some basic mapping logic which I want to implement to all my models 
    }
}

并在MyCoolModel的自定义Mapping MyCoolModel

class MyCoolModelMapping
    : BaseMapping<Model.MyCoolModel>
{        
    public MyCoolModelMapping() 
    {
        Property(r => r.AttributesData).HasColumnType("xml");
    }
}

现在请注意,当EntityFramework请求AttributesData值时,它只是序列化字典,当我从数据库中检索数据时,同样的情况发生,并且EntityFramework将数据设置为字段,然后反序列化对象并将其设置为字典。

最后我不得不overrideOnModelCreating我的DbContext的

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Configurations.Add(new Mappings.BaseMapping<SomeOtherModel>());
        modelBuilder.Configurations.Add(new Mappings.MyCoolModelMapping());
        //Other logic

    }

就是这样! 现在我可以使用业务逻辑中的字典,这个“包装”处理将数据保存到DB并从中检索数据所需的所有内容。

EF Core 2.1引入了一项称为价值转换的新功能:

值转换器允许在读取或写入数据库时​​转换属性值。

此功能大大简化了先前答案中提到的序列化方法,这意味着,引入额外的“帮助器”属性并将字典属性标记为[NotMapped]变得不必要。

以下是为您的案例量身定制的一些代码行(注意,我使用的是Json.NET ,但您可以随意使用您选择的序列化程序):

using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace My.Name.Space
{
    public class MyEntity
    {
        public int Id { get; set; }
        public Dictionary<string, EmployeeLeaveEntitlement> LeaveEntitlementDetails { get; set; } 
    }

    public class MyEntityConfiguration : IEntityTypeConfiguration<MyEntity>
    {
        public void Configure(EntityTypeBuilder<MyEntity> builder)
        {
            builder.ToTable("MyEntity");
            builder.HasKey(e => e.Id);

            builder
            .Property(e => e.LeaveEntitlementDetails)
            .IsRequired()
            .HasConversion(
                v => JsonConvert.SerializeObject(v),
                v => v == null
                    ? new Dictionary<string, EmployeeLeaveEntitlement>() // fallback
                    : JsonConvert.DeserializeObject<Dictionary<string, EmployeeLeaveEntitlement>>(v)
            );
        }
    }
}

我有一个与EF类似的问题,我想将一个查询返回列表转换为类属性的字典等价物。 非常类似于你想如何让LeaveEntitlementDetails包装LeveEntitlementStore例如:

class A
{   
    [NotMapped()]
    public Dictionary<int, DataType> Data {get; set}

    //refers to Data.Values
    public ICollection<DataType> DataAsList {get; set}        

}

我希望DataAsList基本上包装Data.Values

经过大量的反复试验,我发现EF,对于集合(可能更多)来说,通过getter的返回值(而不是setter)来改变。 即从我的db初始化时:

var pollquery=From bb In DBM.Dbi.DataTable.Includes("DataAsList")
              Where bb.Id = id
              Select bb;

ClassA objInstance = pollquery.First();

从来没有调用过ClassA.DataAsList的setter,但是在我的对象内部构造期间getter ....结论:EF使用从属性ClassA.DataAsList的getter中检索的引用,并向其添加对象。

所以我在ObservableCollection中包含了我的getter的DataAsList返回值,并为CollectionChanged args添加了一个处理程序,果然,我的CollectionChanged处理程序正在拾取.Add调用。

所以继承我的hackaround -aroundaround:

class A : INotifyPropertyChanged
{
    //So we can let EF know a complex property has changed
    public event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged;

    //here's our actual data, rather than an auto property, we use an explicit member definition so we can call PropertyChanged when Data is changed
    private Dictionary<int, DataType> m_data = new Dictionary<int, DataType>();
    //not mapped property as it's not mapped to a column in EF DB
    [NotMapped()]
    public Dictionary<int, DataType> Data {
        get { return m_data; }
        set {
            m_data = value;
            //now call PropertyChanged for our Front (so EF will know it's been changed)
            if (PropertyChanged != null) {
                PropertyChanged(this, new PropertyChangedEventArgs("DataAsList"));
            }
        }
    }

    //this is our front for the data, that we use in EF to map data to
    [DebuggerHidden()]
    public ICollection<DataType> DataAsList {
        get {
            ObservableCollection<DataType> ob = new ObservableCollection<DataType>(Data.Values());
            ob.CollectionChanged += Handles_entryListChanged;
            return ob;
        }
        set {
            //clear any existing data, as EF is trying to set the collections value
            Data.Clear();
            //this is how, in my circumstance, i converted my object into the dictionary from an internal obj.Id property'
            foreach (DataType entry in value) {
                entryions.Add(entry.id, entry);
            }
        }
    }
    //This will now catch wind of any changes EF tries to make to our DataAsList property
    public void Handles_entryListChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        //Debugger.Break()
        switch (e.Action) {
            case NotifyCollectionChangedAction.Add:
                foreach (DataType entry in e.NewItems) {
                    m_data.Add(entry.Id, entry);
                }

                break;
            default:
                Debugger.Break();
                break;
        }
    }
}

注意魔术是:

public ICollection<DataType> DataAsList {
    get {
        ObservableCollection<DataType> ob = new ObservableCollection<DataType>(Data.Values());
        ob.CollectionChanged += Handles_entryListChanged;
        return ob;
    }

我们订阅对返回列表所做的任何更改,以及我们处理的Handles_entryListChanged ,并基本上复制所做的任何更改。

如此处所述, 对象序列化之后,一个重要的事情是,当更新实体并更改字典中的项目时,EF更改跟踪不会发现字典已更新的事实,因此您需要显式调用在DbSet <>上更新方法以设置要在更改跟踪器中修改的实体。

也有另一种不错的样本在这里

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM