2014-06-08 86 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); 
    } 
} 
相关问题