简体   繁体   English

正确配置不同属性的 EF Core 一对多映射

[英]Configuring EF Core one to many mapping of different properties correctly

I'm using AutoMapper to map classes from Camille to my own domain classes, which I plan on storing using EF Core in my .NET 5 REST API. I'm using AutoMapper to map classes from Camille to my own domain classes, which I plan on storing using EF Core in my .NET 5 REST API. One particularly nasty class has been causing me a sea of troubles though.一个特别讨厌的 class 给我带来了很多麻烦。 The ParticipantTimeline class contains several dictionaries with stats, as you can see below: ParticipantTimeline class 包含几个带有统计信息的字典,如下所示:

namespace MingweiSamuel.Camille.MatchV4
{
  public class ParticipantTimeline
  {
    [JsonPropertyName("participantId")]
    public int ParticipantId { get; set; }

    [JsonPropertyName("csDiffPerMinDeltas")]
    public IDictionary<string, double> CsDiffPerMinDeltas { get; set; }

    [JsonPropertyName("damageTakenPerMinDeltas")]
    public IDictionary<string, double> DamageTakenPerMinDeltas { get; set; }

    [JsonPropertyName("role")]
    public string Role { get; set; }

    [JsonPropertyName("damageTakenDiffPerMinDeltas")]
    public IDictionary<string, double> DamageTakenDiffPerMinDeltas { get; set; }

    [JsonPropertyName("xpPerMinDeltas")]
    public IDictionary<string, double> XpPerMinDeltas { get; set; }

    [JsonPropertyName("xpDiffPerMinDeltas")]
    public IDictionary<string, double> XpDiffPerMinDeltas { get; set; }

    [JsonPropertyName("lane")]
    public string Lane { get; set; }

    [JsonPropertyName("creepsPerMinDeltas")]
    public IDictionary<string, double> CreepsPerMinDeltas { get; set; }

    [JsonPropertyName("goldPerMinDeltas")]
    public IDictionary<string, double> GoldPerMinDeltas { get; set; }

    [JsonExtensionData]
    public Dictionary<string, object> _AdditionalProperties { get; set; } = new Dictionary<string, object>();

    //Methods omitted for brevity
  }

Up until now, I was mapping to my domain classes as follows:到目前为止,我正在映射到我的域类,如下所示:

CamilleProfile.cs: CamilleProfile.cs:

// Omitted for brevity
CreateMap<ParticipantTimeline, ParticipantTimelineDto>();
CreateMap<KeyValuePair<string, double>, ParticipantTimelineDelta>()
    .ForMember(x => x.Delta, conf => conf.MapFrom(kvp => kvp.Key))
    .ForMember(x => x.Value, conf => conf.MapFrom(kvp => kvp.Value));

ParticipantTimelineDto.cs:参与者时间线Dto.cs:

public class ParticipantTimelineDto
{
    public int ParticipantId { get; set; }
        
    public IEnumerable<ParticipantTimelineDelta> CsDiffPerMinDeltas { get; set; }
        
    public IEnumerable<ParticipantTimelineDelta> DamageTakenPerMinDeltas { get; set; }
        
    public string Role { get; set; }
        
    public IEnumerable<ParticipantTimelineDelta> DamageTakenDiffPerMinDeltas { get; set; }
        
    public IEnumerable<ParticipantTimelineDelta> XpPerMinDeltas { get; set; }
        
    public IEnumerable<ParticipantTimelineDelta> XpDiffPerMinDeltas { get; set; }
        
    public string Lane { get; set; }
        
    public IEnumerable<ParticipantTimelineDelta> CreepsPerMinDeltas { get; set; }
   
    public IEnumerable<ParticipantTimelineDelta> GoldPerMinDeltas { get; set; }
}

ParticipantTimelineDelta.cs:参与者时间线Delta.cs:

public class ParticipantTimelineDelta
{
    public string Delta { get; set; }
    public double Value { get; set; }

    public ParticipantTimelineDelta()
    {
    }
}

This works fine without EF, but now I'm trying to add migrations for identities, and I can't figure out my mappings with EF.这在没有 EF 的情况下工作正常,但现在我正在尝试为身份添加迁移,但我无法弄清楚我与 EF 的映射。 When trying to create migrations, I get the following message:尝试创建迁移时,我收到以下消息:

There are multiple relationships between 'ParticipantTimelineDelta' and 'ParticipantTimelineDto' without configured foreign key properties.在没有配置外键属性的情况下,“ParticipantTimelineDelta”和“ParticipantTimelineDto”之间存在多种关系。 This will cause Entity Framework to create shadow properties on 'ParticipantTimelineDelta' with names dependent on the discovery order.这将导致实体框架在“ParticipantTimelineDelta”上创建影子属性,其名称取决于发现顺序。

This is just a warning, and I understand why it's saying that.这只是一个警告,我理解它为什么这么说。 It's the actual error which then confuses me most.这是让我最困惑的实际错误。 It is as follows:如下:

The entity type 'ParticipantTimelineDelta' requires a primary key to be defined.实体类型“ParticipantTimelineDelta”需要定义一个主键。 If you intended to use a keyless entity type, call 'HasNoKey' in 'OnModelCreating'.如果您打算使用无密钥实体类型,请在“OnModelCreating”中调用“HasNoKey”。 For more information on keyless entity types, see https://go.microsoft.com/fwlink/?linkid=2141943.有关无密钥实体类型的详细信息,请参阅https://go.microsoft.com/fwlink/?linkid=2141943。

It confuses me because I do have a PK defined.这让我很困惑,因为我确实定义了一个 PK。 I don't particularly like the way I'm mapping the deltas, but I've yet to devise a better method of doing so.我不是特别喜欢我映射增量的方式,但是我还没有找到更好的方法来 devise。 Anyways, I was wondering if with my current configuration it is possible to map them correctly at all.无论如何,我想知道以我当前的配置是否有可能完全正确地对它们进行 map。 And if not, how should I map the deltas otherwise?如果没有,我应该如何 map 否则三角洲?

Here are my EF configurations for ParticipantTimeline and ParticipantTimelineDelta:这是我对 ParticipantTimeline 和 ParticipantTimelineDelta 的 EF 配置:

ParticipantTimelineConfiguration.cs:参与者时间线配置.cs:

public class ParticipantTimelineConfiguration : IEntityTypeConfiguration<ParticipantTimelineDto>
{
    public void Configure(EntityTypeBuilder<ParticipantTimelineDto> builder)
    {
        builder.ToTable("ParticipantTimeline");
        builder.HasKey(ps => ps.ParticipantId);
        builder.HasMany<ParticipantTimelineDelta>()
            .WithOne();
    }
}

ParticipantTimelineDeltaConfiguration.cs:参与者时间线DeltaConfiguration.cs:

public class ParticipantTimelineDeltaConfiguration : IEntityTypeConfiguration<ParticipantTimelineDelta>
{
    public void Configure(EntityTypeBuilder<ParticipantTimelineDelta> builder)
    {
        builder.ToTable("ParticipantTimelineDeltas");
        builder.HasKey(d => d.Delta);
    }
}

I've tried defining HasForeignKey on the HasMany().WithOne() statement, to no avail.我尝试在 HasMany().WithOne() 语句上定义 HasForeignKey,但无济于事。

The comment by Ivan Stoev ended up nudging me the right direction. Ivan Stoev 的评论最终为我指明了正确的方向。 I've made the following changes to ParticipantTimelineConfiguration:我对 ParticipantTimelineConfiguration 进行了以下更改:

public class ParticipantTimelineConfiguration : IEntityTypeConfiguration<ParticipantTimelineDto>
{
    public void Configure(EntityTypeBuilder<ParticipantTimelineDto> builder)
    {
        builder.ToTable("ParticipantTimeline");
        builder.HasKey(ps => ps.ParticipantId);
        builder.OwnsMany(pt => pt.CreepsPerMinDeltas, a =>
        {
            a.WithOwner().HasForeignKey("ParticipantTimelineId");
            a.Property<int>("Id");
            a.HasKey("Id");
        });
        builder.OwnsMany(pt => pt.CsDiffPerMinDeltas, a =>
        {
            a.WithOwner().HasForeignKey("ParticipantTimelineId");
            a.Property<int>("Id");
            a.HasKey("Id");
        });
        builder.OwnsMany(pt => pt.DamageTakenDiffPerMinDeltas, a =>
        {
            a.WithOwner().HasForeignKey("ParticipantTimelineId");
            a.Property<int>("Id");
            a.HasKey("Id");
        });
        builder.OwnsMany(pt => pt.DamageTakenPerMinDeltas, a =>
        {
            a.WithOwner().HasForeignKey("ParticipantTimelineId");
            a.Property<int>("Id");
            a.HasKey("Id");
        });
        builder.OwnsMany(pt => pt.GoldPerMinDeltas, a =>
        {
            a.WithOwner().HasForeignKey("ParticipantTimelineId");
            a.Property<int>("Id");
            a.HasKey("Id");
        });
        builder.OwnsMany(pt => pt.XpDiffPerMinDeltas, a =>
        {
            a.WithOwner().HasForeignKey("ParticipantTimelineId");
            a.Property<int>("Id");
            a.HasKey("Id");
        });
        builder.OwnsMany(pt => pt.XpPerMinDeltas, a =>
        {
            a.WithOwner().HasForeignKey("ParticipantTimelineId");
            a.Property<int>("Id");
            a.HasKey("Id");
        });
    }
}

It's not particularly pretty imo, and I expect there to be a better way of doing this.这不是特别漂亮的imo,我希望有更好的方法来做到这一点。 However, this'll do for now.但是,这暂时可以。

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

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