2016-10-08 25 views
2

我希望任何人都可以幫助我。我使用EF6與TPC(每個具體類的表)。有許多表是修訂版保存,意味着表中的每一行都有相同的ID,但是有多個版本。一個版本是當前版本(例如)。 表學生樣本:實體框架不支持

Id Version  Name  CurrentVersion 
1 1   Murtin  false 
1 2   Martin  true 
2 1   Reinold  true 

我在我的模型中使用繼承。所有型號的底座EntityBase

abstract class EntityBase: IEntityBase 
{ 
    [Key] 
    [Column(Order = 0)] 
    public int Id { get; set; } 
} 

對於那些版本保存我使用的下一個基礎類課程的學生

abstract class RevisionBase : EntityBase, IRevisionBase 
{ 
    [Key] 
    [Column(Order = 1)] 
    public int Version { get; set; } 

    [Required] 
    public bool CurrentVersion { get; set; } 
} 

現在我的表我一起工作,所有表

class Student: RevisionBase 
{ 
    [Required] 
    public string Name{ get; set; } 
} 

所以下面的代碼很容易和工作

new DBContext().Student.FirstOrDefault(s=>s.Id=5 && s.CurrentVersion=true) 

對於統一的數據處理,我想總是使用相同的基本方法進行加載。所以我有統一的錯誤處理和日誌記錄。如果它是版本化的表,那麼這個通用get方法應該總是加載當前版本。

private TEntity GeneralGet<TEntity>(int id) where TEntity : EntityBase 
    { 
     using (var ctx = GetContext()) 
     { 
      if (typeof(IRevisionBase).IsAssignableFrom(typeof(TEntity))) 
      { 
       var allResultsId = ctx.Set<TEntity>().Where(l => l.Id == id); 
       var result = allResultsId.ToList().Cast<IRevisionBase>().FirstOrDefault(r => r.CurrentVersion); 
       return result as TEntity; 
      } 
      else  // ansonsten, bei nicht versionierten Objekten 
      { 
       var result = ctx.Set<TEntity>().FirstOrDefault(l => l.Id == id); 
       return result; 
      } 
     } 
    } 

這是完全正常工作,但不幸的是我不得不加載相同ID的所有行並過濾內存中的當前版本。 (ToList加載具有給定ID的所有行。)

有沒有更好的方法?

我不想在這裏有「ToList」。我需要的是一個演員來檢查我的當前版本,或者可能混合方法鏈方式和一個硬編碼過濾器字符串。 (不好,但比這更好)我知道這個表有一列CurrentVersion。我想在加載所有記錄之前檢查它。

回答

1

EF沒有像鑄造(和一般接口)和C#不允許「鑄造」類型。

仍然可以問你在問什麼。我看至少有兩個(可能並不完美,但工作)選項:

(1)像這樣創建一個通用的約束方法:

static IQueryable<TEntity> WhereCurrentVersion<TEntity>(IQueryable<TEntity> source) 
    where TEntity : class, IRevisionBase 
{ 
    return source.Where(e => e.CurrentVersion); 
} 

,並通過反射或動態調用它:

private TEntity GeneralGet<TEntity>(int id) where TEntity : EntityBase 
{ 
    using (var ctx = GetContext()) 
    { 
     var result = ctx.Set<TEntity>().Where(e => e.Id == id); 
     if (result is IQueryable<IRevisionBase>) 
      result = WhereCurrentVersion((dynamic)result); 
     return result.FirstOrDefault(); 
    } 
} 

(2)生成濾波器動態地表達:

private TEntity GeneralGet<TEntity>(int id) where TEntity : EntityBase 
{ 
    using (var ctx = GetContext()) 
    { 
     var result = ctx.Set<TEntity>().Where(e => e.Id == id); 
     if (result is IQueryable<IRevisionBase>) 
     { 
      var parameter = Expression.Parameter(typeof(TEntity), "e"); 
      var predicate = Expression.Lambda<Func<TEntity, bool>>(
       Expression.Property(parameter, nameof(IRevisionBase.CurrentVersion)), 
       parameter); 
      result = result.Where(predicate); 
     } 
     return result.FirstOrDefault(); 
    } 
} 
+1

偉大的伊萬,謝謝。我檢查了第一個版本,它確實有效。只有一條sql語句被髮送到數據庫。這個sql語句包含了哪裏條件。現在我會嘗試第二種方式,只爲自己學習... – Dosihris

+0

哇,第二種方式也在工作!不幸的是我只能投票一次! – Dosihris

+0

順便說一句,歡迎你,夥伴:) :) –

0

您可以製作一個包含屬性的模型,然後您可以使用Cast Extension方法將其轉換爲適當的類型。然後做簡單的LINQ。

public static T Cast<T>(this Object myobj) 
{ 
    Type objectType = myobj.GetType(); 
    var dx = myobj.GetType().GetProperties(); 
    Type target = typeof(T); 
    var x = Activator.CreateInstance(target, false); 
    var z = from source in objectType.GetMembers().ToList() 
      where source.MemberType == MemberTypes.Property 
      select source; 
    var d = from source in target.GetMembers().ToList() 
      where source.MemberType == MemberTypes.Property 
      select source; 
    List<MemberInfo> members = d.Where(memberInfo => d.Select(c => c.Name).ToList().Contains(memberInfo.Name)).ToList(); 
    PropertyInfo propertyInfo; 
    object value; 
    foreach (var memberInfo in members) 
    { 
     propertyInfo = typeof(T).GetProperty(memberInfo.Name);     
     if (Array.Exists(dx, a => a.Name == propertyInfo.Name)) 
     { 
      value = myobj.GetType().GetProperty(memberInfo.Name).GetValue(myobj, null); 
      propertyInfo.SetValue(x, value, null); 
     } 
    } 
    return (T)x; 
} 
+1

謝謝你的想法,但這不可能是一個有用的方法。這是很多反射代碼,並且還創建了很多新的實例。我只想檢查一個列,我實際上在我的EF過濾器... – Dosihris