2017-11-08 27 views
6

मैं वर्तमान में SaveChanges विधि को ओवरराइड करके और प्रतिबिंब का उपयोग करके एक सामान्य तरीके से अपने ऐप में अपनी सभी तालिकाओं पर इतिहास ट्रैकिंग को कार्यान्वित करने का प्रयास कर रहा हूं। एक साधारण मामले के रूप में, मान लीजिए कि मैं की तरह प्रत्येक के लिए मेरे डोमेन वस्तुओं के लिए 2 वर्गों/dbsets और एक इतिहास तालिका डालते हैं निम्नलिखित:SaveChanges में इतिहास ट्रैकिंग को कार्यान्वित करना

DbSet<Cat> Cats { get; set; } 
DbSet<CatHistory> CatHistories { get; set; } 
DbSet<Dog> Dogs { get; set; } 
DbSet<DogHistory> DogHistories { get; set; } 

CatHistory वर्ग की तरह निम्नलिखित (DogHistory इसी योजना इस प्रकार है) दिखता है:

public class CatHistory : HistoricalEntity 
{ 
    public int CatId { get; set; } 

    public virtual Cat Cat{ get; set; } 
} 

मेरा लक्ष्य तब होता है जब कोई ऑब्जेक्ट सहेजा जाता है, मैं उपयुक्त इतिहास तालिका में एक रिकॉर्ड डालना चाहता हूं। प्रतिबिंब का उपयोग करते समय मुझे प्रकार के अंतर पर काबू पाने में परेशानी हो रही है। मेरे वर्तमान प्रयास नीचे है और मैं //TODO: लाइन पर अटक कर रहे:

 var properties = entry.CurrentValues.PropertyNames.Where(x => entry.Property(x).IsModified).ToList(); 

     //get the history entry type from our calculated typeName 
     var historyType = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(x => x.Name == historyTypeName); 

     if(historyType != null) 
     { 

      //modified entries 
      if (dbSet != null && historyDbSet != null && entry.State == EntityState.Modified) 
      { 
      var existingEntry = dbSet.Find(entry.Property("Id").CurrentValue); 

      //create history record and add entry to table 
      var newHistories = GetHistoricalEntities(existingEntry, type, entry); 

      var listType = typeof(List<>).MakeGenericType(new[] { historyType }); 
      var typedHistories = (IList)Activator.CreateInstance(listType); 

      //TODO: turn newHistories (type = List<HistoricalEntity>) into specific list type (List<MyObjectHistory>) so I can addrange on appropriate DbSet (MDbSet<MyObjectHistory>) 

      historyDbSet.AddRange(newHistories); 
      } 
     } 
+0

यदि आप एक इकाई से 'ऐतिहासिक' इकाई में मानचित्र बनाना चाहते हैं, तो [ऑटोमैपर] (http://automapper.org/) – CalC

+1

मेरी ऐतिहासिक संस्थाओं की एक सूची है और मैं एक चर प्रकार के लिए मानचित्र करने की कोशिश कर रहा हूं ।मैं automapper से बहुत परिचित हूं और इस – GregH

उत्तर

1

आप AutoMapper इस्तेमाल कर सकते हैं अपने ऐतिहासिक संस्थाओं मैप करने के लिए।

IList dogs = new List<Dog>() { new Dog { Id = 1, Name = "Alsatian" }, new Dog { Id = 2, Name = "Westie" } }; 
var dogHistoryType = typeof(DogHistory); 
var listType = typeof(List<>).MakeGenericType(new[] { dogHistoryType }); 
var typedHistories = (IList)Activator.CreateInstance(listType); 

mapper.Map(dogs, typedHistories); 

foreach (var historyItem in typedHistories) 
{ 
    this.Add(historyItem); 
} 
+0

को करने का एक तरीका देखा गया है इसके साथ समस्या यह है कि आप 'टाइप किए गए इतिहास [1] को FooHistory' के रूप में उपयोग कर रहे हैं और मुझे वस्तु को' FooHistory' के रूप में नहीं डालना होगा) । कोड में प्रकारों के लिए कोई कठोर संदर्भ नहीं हो सकता है क्योंकि प्रकार परिवर्तनीय – GregH

+0

उपर्युक्त इसे स्पष्ट करने के लिए संपादित किया गया है (टिप्पणी पंक्ति देखें)। क्या आप एक आईएलआईस्ट के साथ जोड़ सकते हैं? यह कम से कम संकलित करता है, लेकिन मैंने कोशिश नहीं की है। – CalC

+0

ठीक है, हम आईएलआईस्ट पर एक फोरैच का उपयोग कर सकते हैं क्योंकि संदर्भ में सीधे 'जोड़ें() 'का उपयोग करें। उपरोक्त संपादन देखें। – CalC

0

मैं जिस तरह से मैं अपने आवेदन में लागू किया है समझाने की कोशिश करेंगे: मैं सिर्फ एक छोटे से परीक्षण बनाया है, उम्मीद है कि यह अपनी स्थिति दोहराता है।

मैंने मॉडल के लिए इतिहास नाम के साथ मॉडल बनाया है जिसके लिए मूल तालिका से रिकॉर्ड हटाने से पहले एप्लिकेशन को सम्मिलित करने की आवश्यकता है।

BaseModel.cs

namespace ProductVersionModel.Model 
{ 
    using System; 
    using System.ComponentModel.DataAnnotations; 
    using System.ComponentModel.DataAnnotations.Schema; 

    /// <summary> 
    /// all common properties of the tables are defined here 
    /// </summary> 
    public class BaseModel 
    { 
     /// <summary> 
     /// id of the table 
     /// </summary> 
     [Key] 
     public int Id { get; set; } 

     /// <summary> 
     /// user id of the user who modified last 
     /// </summary> 
     public string LastModifiedBy { get; set; } 

     /// <summary> 
     /// last modified time 
     /// </summary> 
     public DateTime LastModifiedTime { get; set; } 


     /// <summary> 
     /// record created user id 
     /// </summary> 
     [Required] 
     public string CreatedBy { get; set; } 

     /// <summary> 
     /// record creation time 
     /// </summary> 
     public DateTime CreationTime { get; set; } 

     /// <summary> 
     /// Not mapped to database, only for querying used 
     /// </summary> 
     [NotMapped] 
     public int RowNumber { get; set; } 
    } 
} 

Product.cs

namespace ProductVersionModel.Model 
{ 
    using System; 
    using System.Collections.Generic; 
    using System.ComponentModel.DataAnnotations; 

    /// <summary> 
    /// store detals of the product 
    /// </summary> 
    public class ProductStatus : BaseModel 
    { 
     /// <summary> 
     /// Name of the product 
     /// </summary> 
     [Required, MaxLength(100)] 
     public string Name { get; set; } 


     /// <summary> 
     /// product version validity start date 
     /// </summary> 

     public DateTime ValidFrom { get; set; } 

     /// <summary> 
     /// product version valid till 
     /// </summary> 
     public DateTime? ValidTill { get; set; } 

     /// <summary> 
     /// This field used to keep track of history of a product 
     /// </summary> 
     public int ProductNumber { get; set; } 

    } 
} 

HistoryBaseModel.cs

using System; 
using System.ComponentModel.DataAnnotations; 
using System.ComponentModel.DataAnnotations.Schema; 

namespace ProductVersionModel.Model.History 
{ 
    public class HistroyBaseModel 
    { 

     /// <summary> 
     /// id of the table 
     /// </summary> 
     [Key, DatabaseGenerated(DatabaseGeneratedOption.None)] 
     public int Id { get; set; } 

     public string DeletedBy { get; set; } 

     public DateTime? DeletedTime { get; set; } 
     /// <summary> 
     /// record created user id 
     /// </summary> 
     [Required] 
     public string CreatedBy { get; set; } 

     /// <summary> 
     /// record creation time 
     /// </summary> 
     public DateTime CreationTime { get; set; } 
    } 
} 

ProductStatusHistory.cs

using System; 
using System.Collections.Generic; 
using System.ComponentModel.DataAnnotations; 
using ProductVersionModel.Model.History; 

// ReSharper disable once CheckNamespace 
namespace ProductVersionModel.Model.History 
{ 
    public class ProductStatusHistory : HistroyBaseModel 
    { 

     /// <summary> 
     /// Name of the product 
     /// </summary> 
     [MaxLength(100)] 
     public string Name { get; set; } 

     /// <summary> 
     /// product version validity start date 
     /// </summary> 
     public DateTime ValidFrom { get; set; } 

     /// <summary> 
     /// product version valid till 
     /// </summary> 
     public DateTime? ValidTill { get; set; } 

     /// <summary> 
     /// This field used to keep track of history of a product 
     /// </summary> 
     public int ProductNumber { get; set; } 

    } 
} 

में अपने CrudRepository की विधि हटाएं

public virtual int Delete(List<object> ids, string userName) 
    { 
     try 
     { 
      foreach (var id in ids) 
      { 
       var dbObject = _table.Find(id); 
       HistroyBaseModel historyRecord = null; 
       var modelAssembly = Assembly.Load(nameof(ProductVersionModel)); 
       var historyType = 
        modelAssembly.GetType(
         // ReSharper disable once RedundantNameQualifier - dont remove namespace it is required 
         $"{typeof(ProductVersionModel.Model.History.HistroyBaseModel).Namespace}.{typeof(TModel).Name}History"); 

       if (historyType != null) 
       { 
        var historyObject = Activator.CreateInstance(historyType); 

        historyRecord = MapDeletingObjectToHistoyObject(dbObject, historyObject, userName); 

        DatabaseContext.Entry(historyRecord).State = EntityState.Added; 
       } 
       DatabaseContext.Entry(dbObject).State = EntityState.Deleted; 
      } 
      return DatabaseContext.SaveChanges(); 
     } 
     catch (DbUpdateException ex) 
     { 
      throw HandleDbException(ex); 
     } 
    } 

    protected virtual HistroyBaseModel MapDeletingObjectToHistoyObject(object inputObject, object outputObject, string userName) 
    { 
     var historyRecord = MapObjectToObject(inputObject, outputObject) as HistroyBaseModel; 
     if (historyRecord != null) 
     { 
      historyRecord.DeletedBy = userName; 
      historyRecord.DeletedTime = DateTime.UtcNow; 
     } 
     return historyRecord; 
    } 

    protected virtual object MapObjectToObject(object inputObject, object outputObject) 
    { 
     var inputProperties = inputObject.GetType().GetProperties(); 
     var outputProperties = outputObject.GetType().GetProperties();//.Where(x => !x.HasAttribute<IgnoreMappingAttribute>()); 
     outputProperties.ForEach(x => 
     { 
      var prop = 
       inputProperties.FirstOrDefault(y => y.Name.Equals(x.Name) && y.PropertyType == x.PropertyType); 
      if (prop != null) 
       x.SetValue(outputObject, prop.GetValue(inputObject)); 
     }); 

     return outputObject; 
    } 
तरीकों

कहाँ TModel मॉडल के प्रकार है

public class CrudRepository<TModel> : DataAccessBase, ICrudRepository<TModel> where TModel : class, new() 
public class ProductStatusRepository : CrudRepository<ProductStatus>, IProductStatusRepository 

आप ओवरराइड कर सकते हैं MapDeletingObjectToHistoyObject और MapObjectToObject अपने संबंधित भंडार में यदि आप जटिल तत्वों जैसे बाल तत्व सूची को मानचित्र बनाना चाहते हैं।

संबंधित मुद्दे