强制阻止EF插入一个已经存在的对象

本文关键字:一个 存在 对象 EF 插入 | 更新日期: 2023-09-27 18:05:07

我们有定义了多对多关系的UsersRoles

定义Role的Fluent API:
public RoleMap()
{
    // Primary Key
    this.HasKey(t => t.RoleString);
    // Properties
    this.Property(t => t.RoleString)
        .IsRequired()
        .HasMaxLength(50);
    // Table & Column Mappings
    this.ToTable("Roles");
    this.Property(t => t.RoleString).HasColumnName("Role");
    // Relationships
    this.HasMany(t => t.Users)
        .WithMany(t => t.Roles)
        .Map(m =>
            {
                m.ToTable("UserRoles");
                m.MapLeftKey("Role");
                m.MapRightKey("UserName");
            });
}

下面的代码(如预期的那样)要在Roles中插入一个新的Role,然后在UserRoles中为用户"MrAdmin"插入一个匹配的记录。

var user = db.Users.Find("MrAdmin");
user.Roles.Add(new Role("Administrator"));
db.SaveChanges();

我特别不想从Roles表中查找已经存在的"Administrator"角色。实际的应用程序有一个传入的角色枚举,因此用户根本不需要知道Roles表或其中的任何内容。

换句话说,我知道下面的代码可以工作,但是我希望在更低的级别上操作EF:

var adminRole = db.Roles.Find("Administrator");
var user = db.Users.Find("MrAdmin");
user.Roles.Add(adminRole);
db.SaveChanges();

我想做的是强迫EF避免添加任何记录到Roles表中。

我已经尝试了两种方法:

1)在DB端创建一个INSTEAD OF INSERT触发器,简单地接受插入请求,而不让EF担心它。但英孚仍然知道有些事情很可疑,于是抛出了一个异常。触发:

CREATE TRIGGER [dbo].[tr_DontThrowOnInsert] ON [dbo].[Roles]
INSTEAD OF INSERT
AS 
BEGIN
    SET NOCOUNT ON
    DECLARE @ROLE as varchar(50)
    SELECT @ROLE = [Role] from inserted
    IF EXISTS(SELECT [Role] FROM dbo.Roles WHERE [Role] = @ROLE) 
        UPDATE dbo.Roles 
        SET [Updated] = GetUtCDate() 
        output inserted.[Role]
        WHERE [Role] = @Role
    ELSE 
        INSERT INTO dbo.Roles
        output inserted.[Role]
        SELECT * FROM inserted
        WHERE [Role] not in (SELECT [Role] FROM dbo.Roles)
END

2)重写DBContext中的SaveChanges(),并将可疑条目标记为Unchanged:

public override int SaveChanges()
{
    this.ChangeTracker.Entries<Role>().ForEach(r => r.State = EntityState.Unchanged);
    return base.SaveChanges();
}
异常:

Result Message: System。InvalidOperationException:保存或接受更改失败,因为有多个类型的实体"Manufacturing.Domain。LookupRole具有相同的主键值。确保显式设置的主键值唯一。确保中正确配置了数据库生成的主键数据库和实体框架模型。使用实体设计器用于数据库优先/模型优先配置。使用"HasDatabaseGeneratedOption"流畅的API或'DatabaseGeneratedAttribute'用于Code First配置。

强制阻止EF插入一个已经存在的对象

我决定使用EF 6拦截器。IDbCommandTreeInterceptor和IDbCommandInterceptor…

http://msdn.microsoft.com/en-us/data/dn469464.aspx BuildingBlocks/

相关文章: