[英]Third-party implementation of DbContext, how to also implement IdentityDbContext
我正在使用Audit.NET ,一個開源審計框架,它為Entity Framework和DbContext
提供了一個擴展: AuditDbContext.cs
// Implements DbContext public abstract partial class AuditDbContext : DbContext
我想使用這個Entity Framework擴展在我的項目中實現Audit.NET,因為它會自動執行我需要手動執行的許多步驟(我可以手動使用Audit.NET而不使用Entity Framework延期)。 我DbContext
的問題是我的解決方案存儲庫實現了IdentityDbContext
,當然這也是DbContext
一個實現。
// Implements IdentityDbContext public class MyDataContext : IdentityDbContext<ApplicationUser> { public MyDataContext() : base("DefaultConnection") { } ...
沒有實現IdentityDbContext
現有AuditDbContext
。
我似乎無法想到將這兩者混合在一起並使我的存儲庫使用AuditDbContext
,特別是考慮到AuditDbContext
具有受保護的構造函數,並且DbContext
和IdentityDbContext
都具有protected
方法。 我試圖創建一個名為AuditIdentityDbContext
,它包含每個上下文的private
副本,但是我無法通過這樣做來完成所有接口。
看起來上面的所有3個DbContext
類型都需要繼承,因為protected
成員。 在我的職業生涯中,我覺得多次繼承可能在這種情況下實際上有所幫助,但鑒於這不可能,最好的替代方案是什么?
我唯一能想到的是創建一個繼承自AuditDbContext
或IdentityDbContext<TUser>
的新類,並手動實現剩下的任何內容以匹配另一個的功能。 雖然沒有可以實現的接口類,所以我很確定這不會起作用。 我覺得我必須忽略一些東西。
哎喲!
但你仍然可以找到出路。 IdentityDbContext
沒有什么特別之處,甚至沒有接口! 所以你需要做的就是告訴你自己的DbContext關於用戶和角色並添加一些驗證。
IdentityDbContext
的肉是這樣的:
public virtual IDbSet<TUser> Users { get; set; }
public virtual IDbSet<TRole> Roles { get; set; }
public bool RequireUniqueEmail { get; set; } // this might not be important for you
用您自己的ApplicationUser
和ApplicationRole
替換泛型參數(這兩個類都可以從Identity提供的類繼承)
並添加或混合您自己的方法:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
if (modelBuilder == null)
{
throw new ArgumentNullException("modelBuilder");
}
// Needed to ensure subclasses share the same table
var user = modelBuilder.Entity<TUser>()
.ToTable("AspNetUsers");
user.HasMany(u => u.Roles).WithRequired().HasForeignKey(ur => ur.UserId);
user.HasMany(u => u.Claims).WithRequired().HasForeignKey(uc => uc.UserId);
user.HasMany(u => u.Logins).WithRequired().HasForeignKey(ul => ul.UserId);
user.Property(u => u.UserName)
.IsRequired()
.HasMaxLength(256)
.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("UserNameIndex") { IsUnique = true }));
// CONSIDER: u.Email is Required if set on options?
user.Property(u => u.Email).HasMaxLength(256);
modelBuilder.Entity<TUserRole>()
.HasKey(r => new { r.UserId, r.RoleId })
.ToTable("AspNetUserRoles");
modelBuilder.Entity<TUserLogin>()
.HasKey(l => new { l.LoginProvider, l.ProviderKey, l.UserId })
.ToTable("AspNetUserLogins");
modelBuilder.Entity<TUserClaim>()
.ToTable("AspNetUserClaims");
var role = modelBuilder.Entity<TRole>()
.ToTable("AspNetRoles");
role.Property(r => r.Name)
.IsRequired()
.HasMaxLength(256)
.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("RoleNameIndex") { IsUnique = true }));
role.HasMany(r => r.Users).WithRequired().HasForeignKey(ur => ur.RoleId);
}
和
protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry,
IDictionary<object, object> items)
{
if (entityEntry != null && entityEntry.State == EntityState.Added)
{
var errors = new List<DbValidationError>();
var user = entityEntry.Entity as TUser;
//check for uniqueness of user name and email
if (user != null)
{
if (Users.Any(u => String.Equals(u.UserName, user.UserName)))
{
errors.Add(new DbValidationError("User",
String.Format(CultureInfo.CurrentCulture, IdentityResources.DuplicateUserName, user.UserName)));
}
if (RequireUniqueEmail && Users.Any(u => String.Equals(u.Email, user.Email)))
{
errors.Add(new DbValidationError("User",
String.Format(CultureInfo.CurrentCulture, IdentityResources.DuplicateEmail, user.Email)));
}
}
else
{
var role = entityEntry.Entity as TRole;
//check for uniqueness of role name
if (role != null && Roles.Any(r => String.Equals(r.Name, role.Name)))
{
errors.Add(new DbValidationError("Role",
String.Format(CultureInfo.CurrentCulture, IdentityResources.RoleAlreadyExists, role.Name)));
}
}
if (errors.Any())
{
return new DbEntityValidationResult(entityEntry, errors);
}
}
return base.ValidateEntity(entityEntry, items);
}
當你需要創建ApplicationUserManager
它需要IUserStore
並且用戶存儲的默認實現需要DbContext
因此你可以提供你自己的DbContext,它實際上是從AuditDbContext
繼承的
這應該可以做到這一點,而不必雙重繼承。 萬歲開源!
我在一個項目中遇到了類似的問題。 我們最終做的是做兩個單獨的DbContext
但是它們共享相同的數據庫。
看一下這個答案,它向您展示如何從IdentityDbContext
訪問Users
和Roles
屬性,以及Claims
, Logins
和UserRoles
@trailmax解決方案應該可以工作,但我更新了Audit.NET庫以包含對IdentityDbContext
支持。
提供了一個新類AuditIdentityDbContext ,以便您可以將上下文更改為從該上下文繼承。
您應該將代碼更改為:
public class MyDataContext : AuditIdentityDbContext<ApplicationUser>
{
...
}
注意:我是圖書館老板
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.