我在数据库中有3个表:
歌曲(ID,Title,ReleaseDate)
相册(ID,标题,发布日期)
艺术家(ID,FirstName,LastName)
我有一个相关表格,以便歌曲可以与专辑或艺术家相关,或两者兼而有之:
RelatedSong (ID,ParentID,SongID,TrackNumber)(Album.ID上的外键和ParentID的Artist.ID以及SongID的Song.ID)
因此,使用这四个表,我希望实体框架能够生成允许我在我的MVC项目中简单地执行和运行的模型,但由于外键约束而导致保存失败。如果我设置ParentID = Album.ID,那么它会抱怨Artist.ID为NULL,反之亦然。有什么建议?我正在为现有应用程序重写前端,因此数据库无法更改。我需要知道如何构建模型以便这样做。它位于模型或modelBuilder(Fluent API)中。
专辑模型:
[Table("Album")]
public partial class Album
{
public Album()
{
RelatedAlbums = new HashSet<RelatedAlbum>();
RelatedSongs = new HashSet<RelatedSong>();
}
public Guid ID { get; set; }
[Required]
public string Title { get; set; }
public DateTime ReleaseDate { get; set; }
public virtual ICollection<RelatedAlbum> RelatedAlbums { get; set; }
public virtual ICollection<RelatedSong> RelatedSongs { get; set; }
}
艺术家模特:
[Table("Artist")]
public partial class Artist
{
public Artist()
{
RelatedAlbums = new HashSet<RelatedAlbum>();
RelatedSongs = new HashSet<RelatedSong>();
}
public Guid ID { get; set; }
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
public virtual ICollection<RelatedAlbum> RelatedAlbums { get; set; }
public virtual ICollection<RelatedSong> RelatedSongs { get; set; }
}
相关相册:
[Table("RelatedAlbum")]
public partial class RelatedAlbum
{
public Guid ID { get; set; }
public Guid ParentID { get; set; }
public Guid AlbumID { get; set; }
public virtual Album Album { get; set; }
public virtual Artist Artist { get; set; }
}
相关歌曲:
[Table("RelatedSong")]
public partial class RelatedSong
{
public Guid ID { get; set; }
public Guid ParentID { get; set; }
public Guid SongID { get; set; }
public int? TrackNumber { get; set; }
public virtual Album Album { get; set; }
public virtual Artist Artist { get; set; }
public virtual Song Song { get; set; }
}
曲:
[Table("Song")]
public partial class Song
{
public Song()
{
RelatedSongs = new HashSet<RelatedSong>();
}
public Guid ID { get; set; }
[Required]
public string Title { get; set; }
public DateTime ReleaseDate { get; set; }
public virtual ICollection<RelatedSong> RelatedSongs { get; set; }
}
的DbContext:
public partial class MusicDbContext : DbContext
{
public MusicDbContext()
: base("name=MusicDbContext")
{
}
public virtual DbSet<Album> Albums { get; set; }
public virtual DbSet<Artist> Artists { get; set; }
public virtual DbSet<RelatedAlbum> RelatedAlbums { get; set; }
public virtual DbSet<RelatedSong> RelatedSongs { get; set; }
public virtual DbSet<Song> Songs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Album>()
.HasMany(e => e.RelatedAlbums)
.WithRequired(e => e.Album)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Album>()
.HasMany(e => e.RelatedSongs)
.WithRequired(e => e.Album)
.HasForeignKey(e => e.ParentID)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Artist>()
.HasMany(e => e.RelatedAlbums)
.WithRequired(e => e.Artist)
.HasForeignKey(e => e.ParentID)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Artist>()
.HasMany(e => e.RelatedSongs)
.WithRequired(e => e.Artist)
.HasForeignKey(e => e.ParentID)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Song>()
.HasMany(e => e.RelatedSongs)
.WithRequired(e => e.Song)
.WillCascadeOnDelete(false);
}
}
更新
下面是Create方法的控制器代码。
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID,ParentID,SongID,TrackNumber")] RelatedSong relatedSong)
{
if (ModelState.IsValid)
{
relatedSong.ID = Guid.NewGuid();
db.RelatedSongs.Add(relatedSong);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.ParentID = new SelectList(db.Albums, "ID", "Title", relatedSong.ParentID);
ViewBag.SongID = new SelectList(db.Songs, "ID", "Title", relatedSong.SongID);
return View(relatedSong);
}
更新2:
也许数据库模型不正确或什么?不知道为什么这是不可能的,因为在我看来,这是将数据与多个父母&#34;相关联的最有效方式。我刚刚阅读了另一篇文章,说它不可能(但为什么数据库设计师会允许我这样做?)...
答案 0 :(得分:1)
你的问题在这里:
1
modelBuilder.Entity<Album>()
.HasMany(e => e.RelatedAlbums)
.WithRequired(e => e.Album)
.WillCascadeOnDelete(false);
应该有WithOptional(e => e.Album)
2
modelBuilder.Entity<Album>()
.HasMany(e => e.RelatedSongs)
.WithRequired(e => e.Album)
.HasForeignKey(e => e.ParentID)
.WillCascadeOnDelete(false);
应该有WithOptional(e => e.Album)
3
modelBuilder.Entity<Artist>()
.HasMany(e => e.RelatedAlbums)
.WithRequired(e => e.Artist)
.HasForeignKey(e => e.ParentID)
.WillCascadeOnDelete(false);
应该有WithOptional(e => e.Artist)
4
modelBuilder.Entity<Artist>()
.HasMany(e => e.RelatedSongs)
.WithRequired(e => e.Artist)
.HasForeignKey(e => e.ParentID)
.WillCascadeOnDelete(false);
应该有WithOptional(e => e.Artist)
5
modelBuilder.Entity<Song>()
.HasMany(e => e.RelatedSongs)
.WithRequired(e => e.Song)
.WillCascadeOnDelete(false);
应该有WithOptional(e => e.Song)
您写道它们不是必需的,但在配置中您需要它们。您应该将外键属性设置为可空类型。
[表(&#34; RelatedSong&#34)] public partial class RelatedSong { 公共Guid ID {get;组; }
public Guid? ParentID { get; set; }
...
}
[表(&#34; RelatedAlbum&#34)] public partial class RelatedAlbum { 公共Guid ID {get;组; }
public Guid? ParentID { get; set; }
public Guid? AlbumID { get; set; }
...
}
等等。
答案 1 :(得分:0)
您正在尝试插入“相关歌曲”而没有“相册”,这是
中必需的if (ModelState.IsValid)
{
relatedSong.ID = Guid.NewGuid();
db.RelatedSongs.Add(relatedSong);
db.SaveChanges();
return RedirectToAction("Index");
}
如果你的关系/类型设置略有不同,你可以使用这样的东西
if (ModelState.IsValid)
{
Song song = GetSongById(originalSongId, db);
Song relatedSong = GetSongById(relatedSongId, db);
song.RelatedSongs.Add(relatedSong);
db.SaveChanges();
return RedirectToAction("Index");
}
答案 2 :(得分:0)
你可以在Song表中有两个FK,并使两者都可以为空,在这种情况下,你可以在没有第三张表的情况下将一首歌引用到两者,同时EF可以完美地工作。
歌曲(ID,Title,ReleaseDate, AlbumID可空,ArtistID可以为空)
专辑(ID,Title,ReleaseDate)
艺术家(ID,FirstName,LastName)
答案 3 :(得分:0)
此处更正了您的代码
Song(ID,Title,ReleaseDate)
Album(ID,Title,ReleaseDate)
Artist(ID,FirstName,LastName)
RelatedSong(ID,ParentID,SongID,ArtistID,AlbumID,TrackNumber)
[Table("RelatedSong")]
public partial class RelatedSong
{
public Guid ID { get; set; }
public Guid ParentID { get; set; } // this will be used for the Parent Song
public Guid SongID { get; set; }
public Guid ArtistId {get; set;} // this will be used for artist foreign key
public Guid AlbumId {get; set;} // this will be used for album foreign key
public int? TrackNumber { get; set; }
public virtual Album Album { get; set; }
public virtual Artist Artist { get; set; }
public virtual Song Song { get; set; }
}
modelBuilder.Entity<Album>()
.HasMany(e => e.RelatedSongs)
.WithRequired(e => e.Album)
.HasForeignKey(e => e.ParentID) // here you should use AlbumId and not ParentID
.WillCascadeOnDelete(false);
modelBuilder.Entity<Artist>()
.HasMany(e => e.RelatedSongs)
.WithRequired(e => e.Artist)
.HasForeignKey(e => e.ParentID) // here you should use ArtistId and not ParentID, which you already used it in the Album above
modelBuilder.Entity<Song>()
.HasMany(e => e.RelatedSongs)
.WithRequired(e => e.Song)
.HasForeignKey(e=>e.ParentID); // here you will use the parent id for the song relation
.WillCascadeOnDelete(false);
基于此,你可以解决其他问题,如果有的话
希望这会对你有所帮助