如何避免使用Entity Framework Code First和Web API在数据库中添加重复记录?

时间:2015-03-19 15:41:27

标签: c# entity-framework asp.net-mvc-4 entity-framework-5

我的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构建的。)

1 个答案:

答案 0 :(得分:0)

复合键是一个好主意,可以被视为更好的数据库设计,因为AlbumID和SongID是真正将记录标识为唯一的。

EF提供并发检查,除了更新模型和在else语句中添加try / catch之外,不需要进行许多更改。 This article可以指导您完成整个过程,但会向您的数据库添加一个字段。 This article使用并发检查,但不向数据库添加字段。