我的Web应用程序是使用MVC和Entity Framework Code First构建的。为了解释我的问题,我用一个简化的专辑 - 歌曲例子来描述它:
public abstract class MusicStoreEntity
{
[Display(AutoGenerateField = false), Key, Required, Column(Order = 0)]
public Guid Id { get; set; }
}
[Table(TableName), DataContract]
public class Album : MusicStoreEntity
{
public const string TableName = "Albums";
public virtual Collection<AlbumSong> Songs { get; set; }
}
[Table(TableName), DataContract]
public class Song : MusicStoreEntity
{
public const string TableName = "Songs";
public virtual Collection<AlbumSong> Albums { get; set; }
}
这两个实体是多对多连接的,包含两个外键的独立实体,以及唯一标识符:
[Table(TableName), DataContract]
public class AlbumSong : MusicStoreEntity
{
public const string TableName = "AlbumSongs";
[DataMember, Required]
public Guid AlbumId{ get; set; }
public virtual Album Album { get; set; }
[DataMember, Required]
public Guid SongId { get; set; }
public virtual Song Song { get; set; }
}
使用传入的API调用,如果两个实体尚未连接,则可以创建新实体:
public void SetAlbumSong(Guid albumId, Guid songId) {
var albumSong = DBContext.Set<AlbumSong>().SingleOrDefault(a => a.AlbumId == albumId && a.SongId == songId);
if(albumSong == null) {
var albumSong = new AlbumSong {
AlbumId = albumId,
SongId = songId
}
DBContext.Set<AlbumSong>().Add(albumSong);
DBContext.SaveChanges();
} else {
// update existing albumSong
}
}
但是,当两个API调用几乎同时进入相同的实体ID时,有一个窗口可以在同一个专辑和歌曲之间添加两个AlbumSong实体。
一种解决方案是制作一个Composite Key,其中包含AlbumSong实体中的两个外国ID。这样就不会有两个重复的AlbumSongs,并且会抛出异常 一个类似的解决方案是为AlbumSong添加一个额外的属性,它结合了两个id并要求列是唯一的。
但是,我想知道是否还有其他(更好,更清洁)的解决方案,因为上述解决方案会为我的特定应用带来不必要的变化。
(我的Web应用程序是使用MVC 4和Entity Framework 5构建的。)
答案 0 :(得分:0)
复合键是一个好主意,可以被视为更好的数据库设计,因为AlbumID和SongID是真正将记录标识为唯一的。
EF提供并发检查,除了更新模型和在else语句中添加try / catch之外,不需要进行许多更改。 This article可以指导您完成整个过程,但会向您的数据库添加一个字段。 This article使用并发检查,但不向数据库添加字段。