用于曲目和专辑模型的EF5 Code First Fluent EntityTypeConfiguration

Sea*_*anR 4 entity-framework ef-code-first

我正在为音乐曲目和专辑建模,其中专辑有很多曲目,曲目只能在一个专辑中,并有一个连接表来指定它在专辑列表中的位置.

这是我的模特:

public class Track
{
    public int Id { get; set; }
    public string Name { get; set; }

    public int AlbumTrackId { get; set; }
    public virtual AlbumTrack AlbumTrack { get; set; }
}

public class Album
{
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<AlbumTrack> AlbumTracks { get; set; }
}

public class AlbumTrack
{
    public int AlbumId { get; set; }
    public virtual Album Album { get; set; }

    public int TrackId { get; set; }
    public virtual Track Track { get; set; }

    public int Position { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

和我的EntityTypeConfiguration

public class AlbumTrackConfiguration : EntityTypeConfiguration<AlbumTrack>
{

    public AlbumTrackConfiguration()
    {
        // AlbumTrack has a composite key
        HasKey(at => new {at.AlbumId, at.TrackId});

        // AlbumTrack has one Album, Albums have many AlbumTracks
        HasRequired(at => at.Album)
            .WithMany(a => a.AlbumTracks)
            .HasForeignKey(at => at.AlbumId)
            .WillCascadeOnDelete(true);

        // AlbumTrack has one Track, Tracks have one AlbumTrack
        HasRequired(at => at.Track)
            .WithRequiredPrincipal(t=>t.AlbumTrack)
            .WillCascadeOnDelete(true);
    }

}
Run Code Online (Sandbox Code Playgroud)

专辑和AlbumTracks之间的一对多关系很好,但除了预期之外

[AlbumTrackId] [int] NOT NULL,
Run Code Online (Sandbox Code Playgroud)

Code First不断添加

[AlbumTrack_AlbumId] [int] NOT NULL,
[AlbumTrack_TrackId] [int] NOT NULL
Run Code Online (Sandbox Code Playgroud)

到轨道表.

如何更好地建模Track to Album Track关系,以便只有我指定的属性在db字段中翻译?

[是的,在我的世界中,一首曲目只能存在于一张专辑中!]

谢谢.

NSG*_*aga 5

Track根据建议,使位置成为有意义的一部分.
但是,如果你仍然希望你的"加入"表能够运作 - 而且我个人总是宁愿将这些专辑与他们的'协会',即职位等分开......

要做到这一点,你需要重新组织你的关系.EF/CF无法构建它 - 因为您要求它本身支持或预期的东西.加入,索引表总是期望另一方面的"多重性".

基本上,你AlbumTrack不再是一个"加入"表-但仅仅是一个one-on-oneTrack+你有Album从AlbumTrack FK.

考虑到这一点,您可以执行以下操作 - 并且创建列,索引恰到好处......

public class Track
{
    public int Id { get; set; }
    public string Name { get; set; }
    // public int AlbumTrackId { get; set; }
    public virtual AlbumTrack AlbumTrack { get; set; }
}
public class AlbumTrack
{
    public int TrackId { get; set; } // <== this is a single primary
    public virtual Track Track { get; set; }

    public int AlbumId { get; set; }
    public virtual Album Album { get; set; }

    public int Position { get; set; }
}
public class Album
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<AlbumTrack> AlbumTracks { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

......并且流畅的配置:

modelBuilder.Entity<AlbumTrack>()
    .HasKey(at => new { at.TrackId });
    //.HasKey(at => new { at.AlbumId, at.TrackId });

modelBuilder.Entity<AlbumTrack>()
            .HasRequired(at => at.Track)
            .WithOptional(a => a.AlbumTrack);
            // .WithRequiredPrincipal(x => x.AlbumTrack);

modelBuilder.Entity<AlbumTrack>()
    .HasRequired(at => at.Album)
    .WithMany(a => a.AlbumTracks)
    .HasForeignKey(at => at.AlbumId)
    .WillCascadeOnDelete(true);
Run Code Online (Sandbox Code Playgroud)

......你可以像以下一样使用它:

var album1 = db.Albums.Add(new Album { Name = "Track1", });

var tr1 = db.Tracks.Add(new Track { Name = "Track1", });
var tr2 = db.Tracks.Add(new Track { Name = "Track2", });
var tr3 = db.Tracks.Add(new Track { Name = "Track3", });
var tr4 = db.Tracks.Add(new Track { Name = "Track4", });
var tr5 = db.Tracks.Add(new Track { Name = "Track5", });

db.AlbumTracks.Add(new AlbumTrack { Track = tr1, Album = album1, Position = 1 });
db.AlbumTracks.Add(new AlbumTrack { Track = tr2, Album = album1, Position = 2 });
db.AlbumTracks.Add(new AlbumTrack { Track = tr3, Album = album1, Position = 3 });
db.AlbumTracks.Add(new AlbumTrack { Track = tr4, Album = album1, Position = 4 });
db.AlbumTracks.Add(new AlbumTrack { Track = tr5, Album = album1, Position = 5 });

db.SaveChanges();
Run Code Online (Sandbox Code Playgroud)

(或者你可以'添加'专辑曲目,其余的将进入).

注意:您不再需要复合键 - 因为您的AlbumTrack基本上只依赖于音轨 - 即您only one record对每个音轨都有- 要附加"专辑".
你也不需要// public int AlbumTrackId { get; set; }那个相反的一面,fk在专辑中.这也是旧设置中的错误(因为你需要fk的'两把钥匙' - 加入表).

而且,要补充一点,整个结构"建议"基本上你只是将"分割"轨道表 - 分成两个一对一的表 - 而且你也可以只使用Track/Album.但这有其自身的优势 - 虽然你有额外的连接和读/写(在缺点)你获得了一些灵活性 - 或者稍后你可以通过普通的连接表等关联它们.