【问题标题】:Defining many to many relation in code first entity framework在代码优先实体框架中定义多对多关系
【发布时间】:2013-02-26 00:06:07
【问题描述】:

如下所示,我的模型中有 3 个类。

[Table("UserProfile")]
public class UserProfile
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    
    public string UserName { get; set; }

    public ICollection<MartialArtUserProfile> MartialArtUserProfiles { get; set; }
}

[Table("MartialArt")]
public class MartialArt
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string Name { get; set; }

    public string Description { get; set; }

    public string IconPath { get; set; }

    public string ImagePath { get; set; }

    public ICollection<MartialArtUserProfile> MartialArtUserProfiles { get; set; }
}

public class MartialArtUserProfile
{
    public int UserProfileId { get; set; }
    public UserProfile UserProfile { get; set; }

    public int MartialArtId { get; set; }
    public MartialArt MartialArt { get; set; }
}

我有一个用于多对多关系的配置类,如下所示:

public class MartialArtUserProfileConfiguration : EntityTypeConfiguration<MartialArtUserProfile>
{
    public MartialArtUserProfileConfiguration()
    {
        HasKey(a => new { a.MartialArtId, a.UserProfileId });

        HasRequired(a => a.MartialArt)
            .WithMany(s => s.MartialArtUserProfiles)
            .HasForeignKey(a => a.MartialArtId)
            .WillCascadeOnDelete(false);

        HasRequired(a => a.UserProfile)
            .WithMany(p => p.MartialArtUserProfiles)
            .HasForeignKey(a => a.UserProfileId)
            .WillCascadeOnDelete(false);
    }
}

当我尝试在 Package Manager Console 中运行 Update-Database 定义我的实体关系后,它会说:

在模型生成过程中检测到一个或多个验证错误:

\tSystem.Data.Entity.Edm.EdmEntityType: : EntityType 'MartialArtUserProfile' 没有定义键。定义此 EntityType 的键。 \tSystem.Data.Entity.Edm.EdmEntitySet: EntityType: EntitySet 'MartialArtUserProfiles' 基于没有定义键的类型'MartialArtUserProfile'。

我做错了什么?

提前致谢,

【问题讨论】:

  • 您真的需要 MartialArtUserProfile 类还是只是使用它来建立多对多关系?
  • 我只是用它来建立多对多的关系。 @嗅探器

标签: c# entity-framework ef-code-first entity-framework-migrations


【解决方案1】:

如果我理解您只是尝试使用传递表创建多对多。如果是这样,这是解决此问题的另一种方法。使用 Fluent API 映射如下。您可以将UserProfileToMartialArt 更改为您想要的表名。让 EF 为您创建中间地带,而不是创建 MartialArtUserProfile 模型。这还指定了您的密钥,这些密钥可以帮助您绕过错误。

modelBuilder.Entity<UserProfile>()
    .HasMany(b => b.MartialArts)
    .WithMany(a => a.UserProfiles)
    .Map(m => m.MapLeftKey("MartialArtId")
        .MapRightKey("UserProfileId")
        .ToTable("UserProfileToMartialArt"));

在武术模型中放置

public IList<UserProfile> UserProfiles { get; set; }   

在 UserProfile 模型中放置

public IList<MartialArt> MartialArts { get; set; }  

【讨论】:

  • 我收到了评论反馈,使用 .Map 流畅地定义上述关系并不是最佳实践,因为解决方案可以在更改后编译,直到运行时,这是显而易见的。您是否建议使用反射或其他方式(在我的脑海中,将实体表属性和映射分配给常量?)
【解决方案2】:

尝试这样做:

[Table("UserProfile")]
public class UserProfile
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string UserName { get; set; }

    [InverseProperty("UserProfiles")]
    public IList<MartialArt> MartialArts { get; set; }
}

[Table("MartialArt")]
public class MartialArt
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string Name { get; set; }

    public string Description { get; set; }

    public string IconPath { get; set; }

    public string ImagePath { get; set; }

    [InverseProperty("MartialArts")]
    public IList<UserProfile> UserProfiles { get; set; }
}

【讨论】:

  • 这对我很有效。尽管我处于一种我关心只有一个实体与另一个实体链接的情况。可以用这个吗?起初我只有一个 IList Others {get;set;} 但它不能正常工作
  • 你说的是一对一的关系吗?
  • 我说的是(单向)多对多关系......单向我的意思是在我的代码中我想要一个导航属性。这根本不是什么大问题,我只是想知道如何,如果可能的话
  • 这可以通过将映射到数据库上的多对多表的中间类来完成。使用上面的代码,EF 构建了多对多表,但您无法从代码中访问它。但是,您可以重新设计代码,以便您拥有一个具有 MartialArts 和 UserProfiles 外键的类,但被认为是它自己的实体,用作多对多链接。在这种情况下,您可以完成您想要做的事情。
  • @GusCrawford 按照惯例。
【解决方案3】:

在 EntityFramework 6.1 中,您无需执行任何操作 - 只需将这两种类型的集合添加到每个类中,一切都会到位。

public class UserProfile {
    public int Id { get; set; }
    public string UserName { get; set; }
    public virtual ICollection<MartialArt> MartialArts { get; set; }

    public UserProfile() {
        MartialArts = new List<MartialArt>();
    }
}

public class MartialArt {
    public int Id { get; set; }
    public string Name { get; set; }
    // *snip*
    public virtual ICollection<UserProfile> UserProfiles { get; set; }

    public MartialArt() {
        UserProfiles = new List<UserProfile>();
    }
}

【讨论】:

  • 太棒了,为我工作。这是应该的。去 6.1
  • 如果这是 Admir 上述回答 (stackoverflow.com/a/15328042/489396) 的演变,并且“就位”是基于约定的,那么映射表之间需要哪些约定?
  • @GusCrawford - 映射表对您的代码完全隐藏,只需在代码中包含两个相反对象的集合即可创建它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-20
  • 2013-03-17
  • 2013-03-14
  • 1970-01-01
  • 2011-07-28
  • 1970-01-01
相关资源
最近更新 更多