我们Users
和Roles
定义了多对多关系。
定义角色的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");
});
}
以下代码(按预期方式)希望在角色中插入新角色,然后在UserRoles中为用户“MrAdmin”插入匹配记录。
var user = db.Users.Find("MrAdmin");
user.Roles.Add(new Role("Administrator"));
db.SaveChanges();
我非常特别地不想从Roles表中查找已存在的“Administrator”角色。实际应用程序具有传入的角色枚举,因此用户无需了解角色表或其任何内容。
换句话说,我知道以下代码有效,但我希望在较低级别操作EF:
var adminRole = db.Roles.Find("Administrator");
var user = db.Users.Find("MrAdmin");
user.Roles.Add(adminRole);
db.SaveChanges();
我要做的是强制EF避免将任何(或已经存在的)记录添加到角色表中。
我尝试了两种方法:
1)在数据库端创建一个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(),并将可疑条目标记为未更改:
public override int SaveChanges()
{
this.ChangeTracker.Entries<Role>().ForEach(r => r.State = EntityState.Unchanged);
return base.SaveChanges();
}
例外:
结果消息:System.InvalidOperationException:保存或接受更改失败,因为多个类型的实体 'Manufacturing.Domain.LookupRole'具有相同的主键值。 确保显式设置的主键值是唯一的。确保这件事 数据库生成的主键在中正确配置 数据库和实体框架模型。使用实体设计器 用于Database First / Model First配置。使用 'HasDatabaseGeneratedOption'流畅的API或 用于Code First配置的“DatabaseGeneratedAttribute”。
答案 0 :(得分:0)
我决定使用EF 6拦截器。 IDbCommandTreeInterceptor和IDbCommandInterceptor ...
http://msdn.microsoft.com/en-us/data/dn469464.aspx#BuildingBlocks/