2016-11-14 54 views
0

我有一個MSSQL數據庫和一個帶有EntityFramework Core的ASP.NET MVC Core WebApi項目。EntityFramework將執行查詢的用戶傳遞給MSSQL

我有自定義表稱爲用戶和BlogPosts。 我想更新BlogPosts列「ModifiedById」每次它由用戶表中的Id更新。

我想爲這樣的操作使用SQL觸發器,但我找不到一種方法來傳遞用戶ID與每個查詢。缺點是我需要每個表一個觸發器。

有沒有更好的解決方案?

是的,有:)如所提出的,最好的選擇是覆蓋DbContext的SaveChanges()方法。

關於, p。

+0

這隻有在您使用AD連接到SQL Server實例時才能起作用,然後您可以插入他們的SQL Server關聯ID或AD用戶名。這將在觸發器中可用,因爲您無法將信息傳遞給觸發器。 – Igor

+1

正在搜索CURRENT_USER? https://msdn.microsoft.com/zh-cn/library/ms176050.aspx?f=255&MSPPError=-2147217396 – tym32167

+0

@ tym32167,CURRENT_USER或USER_NAME(USER_ID())從Connection字符串返回用戶。 我需要從我的表用戶有一個用戶,這意味着我需要把他放在我的DbContext的某個地方。但是哪裏? –

回答

2

我通常通過繼承和覆蓋來實現SaveChanges() - 這與Code First一起工作,並且必須手動將審計字段添加到每個類。

public abstract class TrackedEntity 
{ 
    public DateTime CreatedDate { get; set; } 
    public DateTime ModifiedDate { get; set; } 
    public string ModifiedBy { get; set; } 
} 


public class SomeOtherClass : TrackedEntity 
{ 
    // Class specific properties here 
} 

,然後在你的DbContext

private User _loggedOnUser 

    public override int SaveChanges() 
    { 
     var timestamp = DateTime.Now; 

     // First look at new items these need created date adding 
     var addedEntities = ChangeTracker.Entries().Where(x => x.State == EntityState.Added).Select(x => x.Entity); 

     foreach (var addition in addedEntities) 
     { 
      var entity = addition as TrackedEntity; 

      if (entity != null) 
      { 
       entity.CreatedDate = timestamp; 
       entity.ModifiedDate = timestamp; 
       entity.ModifiedBy = _loggedOnUser; 
      } 
     } 

     // Next look at modified entries 
     var modifiedEntities = ChangeTracker.Entries().Where(x => x.State == EntityState.Modified || x.State == EntityState.Deleted); 

     foreach (var update in modifiedEntities) 
     { 
      // Only check tracked entities if modified 
      if (update.State == EntityState.Modified) 
      { 
       var tracked = update.Entity as TrackedEntity; 

       if (tracked != null) 
       { 
        tracked.ModifiedDate = timestamp; 
        tracked.ModifiedBy = _loggedOnUser; 
       } 
      } 
     } 
    } 

,並得到用戶

private void GetUser() 
    { 

     string user = string.Empty; 

     // if we have an http context, lets try it first 
     if (System.Web.HttpContext.Current != null) 
     { 
      if (System.Web.HttpContext.Current.User.Identity != null && System.Web.HttpContext.Current.User.Identity.IsAuthenticated) 
       user = System.Web.HttpContext.Current.User.Identity.Name; 
     } 

     if (user == null) 
      user = System.Threading.Thread.CurrentPrincipal.Identity.Name; 

     _loggedOnUser = this.Users.SingleOrDefault(x => x.Username == user); 
    } 
+0

如果將'class TrackedEntity'更改爲'interface ITrackedEntity',它會更好/更具可擴展性。這允許您的類型進行裝飾,並且不會將其限制爲基本類型。 – Igor

+0

@Igor這取決於你的用例。你沒有錯,但我不認爲它會自動「更好」 –

+0

是否有特別的理由避免''SaveChanges()''中鑄造'IEnumerable.OfType ()'?沒有判斷力,只是好奇:) – Gusdor

0

如果您使用的WebMatrix:

using WebMatrix.WebData; 
//... 
BlogPost bp = new BlogPost() 
{ 
    // other properties 
    ModifiedById = WebSecurity.CurrentUserId, 
} 
1

感謝@Igor和@ STE-FU。

至於建議我已經被覆蓋的的SaveChanges如下:

public override int SaveChanges() 
    { 
     var timeStamp = DateTime.UtcNow; 
     var userId = this.GetAuthenticatedUser(); 

     this.HandleAddedEntities(userId, timeStamp); 
     this.HandleModifiedEntities(userId, timeStamp); 

     return base.SaveChanges(); 
    } 
    private void HandleAddedEntities(Guid userId, DateTime timeStamp) 
    { 
     var entities = ChangeTracker.Entries() 
         .Where(x => x.Entity is IAddedEntity && 
            x.State == EntityState.Added) 
         .Select(x => x.Entity as IAddedEntity); 

     foreach (var e in entities) 
     { 
      e.CreatedById = userId; 
      e.CreatedOn = timeStamp; 
     } 
    } 

    private void HandleModifiedEntities(Guid userId, DateTime timeStamp) 
    { 
     var entities = ChangeTracker.Entries() 
         .Where(x => x.Entity is IModifiedEntity && 
            (x.State == EntityState.Added || 
             x.State == EntityState.Modified)) 
         .Select(x => x.Entity as IModifiedEntity); 

     foreach (var e in entities) 
     { 
      e.ModifiedById = userId; 
      e.ModifiedOn = timeStamp; 
     } 
    } 

正如我所使用的接口,因爲這樣我願意接受其他「通用觸發」在需要時的評論中指出。

感謝球員們的額外快速反應。

+1

很高興爲你工作。請考慮接受答案(參見[如何接受答案](http://meta.stackexchange.com/a/5235))。我會推薦@ ste-fu的回答,因爲那是最有幫助的,讓你去你需要去的地方。 – Igor

+0

我做過了,但由於我的排名不可見。 –

+0

有2個選項:upvote/downvote(你剛剛做了什麼)。這還沒有提供給您(15點以下時)。你使用箭頭來做到這一點,你可以在你的問題(或其他)上儘可能多地回答你認爲合適的答案。雖然僅通過提問者(在這種情況下)使用答案旁邊的複選框來標記答案,但只有一個答案可以標記爲「答案」。 – Igor