【问题标题】:Forcefully Preventing EF from Inserting an Already Existing Object强制阻止 EF 插入已经存在的对象
【发布时间】:2015-07-28 18:10:11
【问题描述】:

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

定义角色的 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 中插入一个新角色,然后在 UserRoles 中为用户“MrAdmin”插入一条匹配记录。

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

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

换句话说,我知道以下代码可以工作,但我希望在较低级别操作 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 TRIGGER,以简单地接受插入请求,而不让 EF 担心。但是 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();
}

例外:

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

【问题讨论】:

    标签: c# sql-server entity-framework ef-code-first


    【解决方案1】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-29
      • 1970-01-01
      • 2018-02-15
      • 2021-01-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多