实体框架:避免插入重复项

时间:2011-03-21 11:33:42

标签: c# .net linq entity-framework

说,我有以下概念模型,有些标签有多个标签(多个,所以它是多对多的关系),加上每个标签都属于一个特定的类别。

我的数据来自外部资源,在插入之前我想确保没有添加重复的标记。

更新了代码段:

static void Main(string[] args)
    {
        Story story1 = new Story();
        story1.Title = "Introducing the Entity Framework";
        story1.Tags.Add(new Tag { Name = ".net",  });
        story1.Tags.Add(new Tag { Name = "database" });

        Story story2 = new Story();
        story2.Title = "Working with Managed DirectX";
        story2.Tags.Add(new Tag { Name = ".net" });
        story2.Tags.Add(new Tag { Name = "graphics" });

        List<Story> stories = new List<Story>();
        stories.Add(story1);
        stories.Add(story2);

        EfQuestionEntities db = new EfQuestionEntities();

        Category category = (from c in db.Categories
                             where c.Name == "Programming"
                             select c).First();

        foreach (Story story in stories)
        {
            foreach (Tag tag in story.Tags)
            {
                Tag currentTag = tag;
                currentTag = GetTag(tag.Name, category, db);
            }

            db.Stories.AddObject(story);
        }

        db.SaveChanges();
    }

    public static Tag GetTag(string name, Category category, EfQuestionEntities db)
    {
        var dbTag = from t in db.Tags.Include("Category")
                    where t.Name == name
                    select t;

        if (dbTag.Count() > 0)
        {
            return dbTag.First();
        }

        var cachedTag = db.ObjectStateManager.GetObjectStateEntries(EntityState.Added).
            Where(ose => ose.EntitySet == db.Tags.EntitySet).
            Select(ose => ose.Entity).
            Cast<Tag>().Where(x => x.Name == name);

        if (cachedTag.Count() != 0) 
        {
            return cachedTag.First();
        }

        Tag tag = new Tag();
        tag.Name = name;
        tag.Category = category;

        db.Tags.AddObject(tag);

        return tag;
    }

但是,我得到一个关于ObjectContext中已存在的具有相同EntityKey的对象的异常。

此外,如果我删除了else语句,我将获得有关违反FK约束的异常,因此它的Category属性似乎设置为null。

1 个答案:

答案 0 :(得分:4)

我和EF有同样的问题。这就是我最终做的事情:

  1. 不是自己story1.Tags.Add(new Tag { Name = ".net", }),而是通过这样的辅助方法路由所有Tag创建:story1.Tags.Add(GetTag(".net"))
  2. GetTag方法检查上下文中的标记,以查看它是否应该像您一样返回现有实体。如果是,则返回。
  3. 如果没有现有实体,它会检查ObjectStateManager以查看是否有Tag个实体添加到上下文但尚未写入数据库。如果找到匹配的Tag,则返回该值。
  4. 如果仍未找到Tag,则会创建一个新的Tag,将其添加到上下文中,然后将其返回。
  5. 实质上,这将确保在整个程序中将使用任何Tag的实例(无论是已存在还是刚创建)。

    我的项目解除了一些示例代码(使用InventoryItem代替Tag,但您明白了。)

    步骤3中的检查完成如下:

    // Second choice: maybe it's not in the database yet, but it's awaiting insertion?
    inventoryItem = context.ObjectStateManager.GetObjectStateEntries(EntityState.Added)
        .Where(ose => ose.EntitySet == context.InventoryItems.EntitySet)
        .Select(ose => ose.Entity)
        .Cast<InventoryItem>()
        .Where(equalityPredicate.Compile())
        .SingleOrDefault();
    
    if (inventoryItem != null) {
        return inventoryItem;
    }
    

    如果在步骤3中找不到Tag,则这是第4步的代码:

    inventoryItem = new InventoryItem();
    context.InventoryItems.AddObject(inventoryItem);
    return inventoryItem;
    

    <强>更新

    它应该像这样使用:

    Story story1 = new Story();
    story1.Title = "Introducing the Entity Framework";
    story1.Tags.Add(GetTag(".net", category, db));
    story1.Tags.Add(GetTag("database", category, db));
    
相关问题