2014-06-08 144 views
0

當新的Post輸入到系統中時,需要實例化若干Tags並將其與Post實例關聯。這些Tags中的一些已經存在於數據庫中,而其他的則不需要插入。如何在連接之前檢查實體是否存在?

一個例子:

var post = new Post { 
    Slug = "hello-world", 
    Title = "Hello, World!", 
    Content = "this is my first post.", 
    Tags = new List<Tag>() 
}; 

var tag = new Tag { Name = "introduction" }; 
post.Tags.Add(tag); 

當關聯Tag沒有在數據庫中存在,我可以依靠簡單的調用DbSet<T>.Add同時插入後和相關標籤到數據庫。 但是,嘗試插入帶有已存在於數據庫中的關聯標籤的帖子會導致標籤表上的主鍵違例。

在試圖解決這個問題,我試圖Attach每個標籤,當標籤在數據庫中已經存在,但否則,拋出一個異常有以下內部異常,其工作原理超級數據庫上下文:

INSERT語句與FOREIGN KEY約束「FK_dbo.TagPosts_dbo.Tags_Tag_Name」衝突。衝突發生在 數據庫「EF.Domain.BlogDb」,表「dbo.Tags」,列 '名稱'。該語句已終止。「}

我要插入與後到數據庫僅在需要時,相關的標籤。我怎樣才能做到這一點?

+0

完整的代碼它幫助:https://gist.github.com/anonymous/f98d1a4d6d760b87c58e –

回答

2

你的困境是挺有意思的。如果你不會使用一個通用的存儲庫,但它知道要附加實體的主鍵,你可以只使用這樣的特定代碼庫:

var tagExists = Tags.Any(t => t.Name == tag.Name); 

var tag = Tags.Find(tag.Name); 

但是在你的情況下,我們需要一個更一般的方法,比如獲取Repository類使用的實體的主鍵,而不管實體的類型如何。要做到這一點我創建的類的DbContext兩種拓方法:

public static IList<string> GetPrimaryKeyNames<TEntity>(this DbContext context) 
    where TEntity : class 
{ 
    var objectContext = ((IObjectContextAdapter)context).ObjectContext; 
    var set = objectContext.CreateObjectSet<TEntity>(); 

    return set.EntitySet.ElementType 
     .KeyMembers 
     .Select(k => k.Name) 
     .ToList(); 
} 

public static IList<object> GetPrimaryKeyValues<TEntity>(this DbContext context, TEntity entity) 
    where TEntity : class 
{ 
    var valueList = new List<object>(); 
    var primaryKeyNames = context.GetPrimaryKeyNames<TEntity>(); 

    foreach(var propertyInfo in entity.GetType().GetProperties()) 
    { 
     if (primaryKeyNames.Contains(propertyInfo.Name)) 
     { 
      valueList.Add(propertyInfo.GetValue(entity)); 
     } 
    } 

    return valueList; 
} 

利用這些方法,您可以更改存儲庫類Attach方法如下所示:萬一

public void Attach(TEntity entity) 
{ 
    var storeEntity = _context.Set<TEntity>().Find(
     _context.GetPrimaryKeyValues(entity).ToArray()); 

    if (storeEntity != null) 
    { 
     _context.Entry(storeEntity).State = EntityState.Detached; 
     _context.Set<TEntity>().Attach(entity); 
    } 
} 
相關問題