热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

实体框架如果不存在则添加更新-EntityFrameworkAddifnotexistwithoutupdate

IlikethefactthatAddOrUpdateletsyouspecifyafiltertochecktoavoidaddingduplicates.But

I like the fact that AddOrUpdate let's you specify a filter to check to avoid adding duplicates. But I would like similar functionality without the update.

我喜欢AddOrUpdate让我们指定一个过滤器来检查以避免添加重复。但是我希望类似的功能不需要更新。

Right now I do something like this:

现在我做了这样的事情:

var checkProfile = from p in db.Profile
    where p => p.LastName == newProfile.lastName
         && p => p.FirstName == newProfile.firstName
         && p => p.Middle== newProfile.middle
    select p;
if (checkProfile.FirstOrDefault() == null)
{
    db.Profile.Add(newProfile);
    db.SaveChanges();
}

I know I can do something like this:

我知道我可以这样做:

db.Profile.AddOrUpdate(p => new {p.LastName, p.FirstName, p.Middle}, newProfile);
db.SaveChanges();

But I would rather skip modifying the data in this case.

但在这种情况下,我宁愿跳过修改数据。

The first example does what I want but with more code. Is there a simpler/cleaner way to do what I want in the first example?

第一个示例执行我想要的操作,但是需要更多的代码。在第一个例子中,有没有更简单/更干净的方法来做我想做的事情?

Update:

更新:

I like Ognyan Dimitrov's suggestion. I'm trying to implement it. My models inherit from BaseEntity. Can I put a generic version of that there?

我喜欢迪米特洛夫的建议。我正在尝试实现它。我的模型继承自BaseEntity。我可以在那里放一个通用的版本吗?

My model is defined:

我的模型定义:

public class Address :BaseEntity
{

My BaseEntity:

我的BaseEntity:

public class BaseEntity 
{
    public virtual T AddIfNotExists(T entity, Expression> predicate = null)
    {
        var exists = predicate != null ? DbSet.Any(predicate) : DbSet.Any();
        return !exists ? DbSet.Add(entity) : null;
    }
}

I'm getting errors for Any(...) and Add(...). The error for Add(...) is 'An object reference is required for the non-static field, method, or property 'System.Data.Entity.DbSet.Add(object)' '

我得到的错误为任何(…)和添加(…)。Add(…)的错误是“非静态字段、方法或属性需要一个对象引用”System.Data.Entity.DbSet.Add(object)“

Should I be using this.Add(object) ?

我应该使用this.Add(object)吗?

Update 2:

更新2:

I've created this code:

我创建了这个代码:

public static class DbSetExtensions
{
    public static T AddIfNotExists(this DbSet dbSet, T entity, Expression> predicate = null) where T : class, new()
    {
        var exists = predicate != null ? dbSet.Any(predicate) : dbSet.Any();
        return !exists ? dbSet.Add(entity) : null;
    }

}

Now I'm trying to call it like this, but it's not correct. Forgive my lack of understanding.

我试着这样称呼它,但它不正确。请原谅我的不理解。

_db.ProfileIdentifier.AddIfNotExists(newIdentifier,
            pi => new {pi.ProfileId, pi.ProfileIdentifierTypeId, pi.ProfileIdentifierValue});

Update - Solution:

更新——解决方案:

I can call the DbSetextensions like this:

我可以这样命名dbsetex张力:

_db.ProfileIdentifier.AddIfNotExists(newIdentifier,
            pi => pi.ProfileId == profileId &&  
            pi.ProfileIdentifierTypeId == (int)type &&  
            pi.ProfileIdentifierValue == value);

Thanks a lot for working with me Ognyan!!!

非常感谢你和我一起工作!!!

6 个解决方案

#1


25  

Have you tried to check if the entity exists and if not - add it? Like this :

是否尝试检查实体是否存在,如果不存在,添加它?是这样的:

UPDATE

更新

using System.Linq.Expressions;
    public class ContextWithExtensionExample
    {
        public void DoSomeContextWork(DbContext context)
        {
            var uni = new Unicorn();
            context.Set().AddIfNotExists(uni , x => x.Name == "James");
        }
    }

    public static class DbSetExtensions
    {
        public static T AddIfNotExists(this DbSet dbSet, T entity, Expression> predicate = null) where T : class, new()
        {
            var exists = predicate != null ? dbSet.Any(predicate) : dbSet.Any();
            return !exists ? dbSet.Add(entity) : null;
        }
    }

You can use this method directly and remember to call DbContext.SaveChanges() after the call.

您可以直接使用这个方法,并记住在调用之后调用DbContext.SaveChanges()。

#2


5  

Quoted from MSDN EF article.

引用MSDN的文章。

Insert or update pattern

插入或更新模式

A common pattern for some applications is to either Add an entity as new (resulting in a database insert) or Attach an entity as existing and mark it as modified (resulting in a database update) depending on the value of the primary key. For example, when using database generated integer primary keys it is common to treat an entity with a zero key as new and an entity with a non-zero key as existing. This pattern can be achieved by setting the entity state based on a check of the primary key value.

一些应用程序的常见模式是,根据主键的值将实体添加为新的(导致数据库插入),或者将实体附加为现有的,并将其标记为修改的(导致数据库更新)。例如,当使用数据库生成的整数主键时,通常会将具有0键的实体视为新的实体,而将具有非0键的实体视为现有实体。可以通过基于主键值的检查设置实体状态来实现此模式。

Note that when you change the state to Modified all the properties of the entity will be marked as modified and all the property values will be sent to the database when SaveChanges is called.

注意,当您将状态更改为Modified时,实体的所有属性将被标记为Modified,当调用SaveChanges时,所有属性值将被发送到数据库。

context.Entry(blog).State = blog.BlogId == 0 ? 
                           EntityState.Added : 
                           EntityState.Modified; 

context.SaveChanges(); 

#3


5  

I used something like, read these two posts to make my code. I hope to help those in need of a similar signature to AddOrUpdate.

我用这两篇文章来写代码。我希望能帮助那些需要AddOrUpdate类似签名的人。

Entity Framework Add if not exist without update

实体框架如果不存在则添加更新

Making AddOrUpdate change only some properties

做AddOrUpdate只更改一些属性

using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace System.Data.Entity.Migrations
{
    //
    // Summary:
    //     Metodos de extensão para System.Data.Entity.IDbSet
    public static class DbSetMigrationsGustavoExtensions
    {
        /// 
        /// Adiciona uma entidade se ela não existe ainda
        /// Assinatura semelhante ao AddOrUpdate
        /// 
        /// 
        /// Set onde serão adicionadas as entidades
        /// Campos usados na comparação
        /// Entidades para adicionar
        public static void AddIfNotExists(this IDbSet set, Expression> identifierExpression, params TEntity[] entities) where TEntity : class
        {

            var identifyingProperties = GetProperties(identifierExpression).ToList();
            var parameter = Expression.Parameter(typeof(TEntity));
            foreach (var entity in entities)
            {
                var matches = identifyingProperties.Select(pi => Expression.Equal(Expression.Property(parameter, pi.Name), Expression.Constant(pi.GetValue(entity, null))));
                var matchExpression = matches.Aggregate(null, (agg, v) => (agg == null) ? v : Expression.AndAlso(agg, v));

                var predicate = Expression.Lambda>(matchExpression, new[] { parameter });
                if (!set.Any(predicate))
                {
                    set.Add(entity);
                }
            }
        }

        private static IEnumerable GetProperties(Expression> exp) where T : class
        {
            Debug.Assert(exp != null);
            Debug.Assert(exp.Body != null);
            Debug.Assert(exp.Parameters.Count == 1);

            var type = typeof(T);
            var properties = new List();

            if (exp.Body.NodeType == ExpressionType.MemberAccess)
            {
                var memExp = exp.Body as MemberExpression;
                if (memExp != null && memExp.Member != null)
                    properties.Add(type.GetProperty(memExp.Member.Name));
            }
            else if (exp.Body.NodeType == ExpressionType.Convert)
            {
                var unaryExp = exp.Body as UnaryExpression;
                if (unaryExp != null)
                {
                    var propExp = unaryExp.Operand as MemberExpression;
                    if (propExp != null && propExp.Member != null)
                        properties.Add(type.GetProperty(propExp.Member.Name));
                }
            }
            else if (exp.Body.NodeType == ExpressionType.New)
            {
                var newExp = exp.Body as NewExpression;
                if (newExp != null)
                    properties.AddRange(newExp.Members.Select(x => type.GetProperty(x.Name)));
            }

            return properties.OfType();
        }

        /// 
        /// Faz um set.Any(predicate)
        /// Se não existe nada no set então adiciona
        /// 
        /// 
        /// Set onde será adicionada a entidade
        /// Condição (exemplo: dbUser => dbUser.Nome == "Gustavo")
        /// Entidade para adicionar
        /// 
        public static T AddIfNotExists(this IDbSet set, Expression> predicate, T entity) where T : class, new()
        {
            return !set.Any(predicate) ? set.Add(entity) : null;
        }
    }
}

#4


2  

The solution is OK, when you have to add just one item, but it's very expensive in terms of performance in case you have to add multiple items. I think there is a better solution:

解决方案是可以的,当您只需要添加一个项目时,但是如果您需要添加多个项目,那么在性能方面非常昂贵。我认为有更好的解决办法:

public static class DbSetExtensions
{
    public static EntityEntry AddIfNotExists(this DbSet dbSet, TEnt entity, Func predicate) where TEnt : class
    {
        var exists = dbSet.Any(c => predicate(entity).Equals(predicate(c)));
        return exists
            ? null
            : dbSet.Add(entity);
    }

    public static void AddRangeIfNotExists(this DbSet dbSet, IEnumerable entities, Func predicate) where TEnt : class
    {
        var entitiesExist = from ent in dbSet
            where entities.Any(add => predicate(ent).Equals(predicate(add)))
            select ent;

        dbSet.AddRange(entities.Except(entitiesExist));
    }
}

So later it can be used like this:

之后它可以这样使用:

using (var cOntext= new MyDbContext())
{
    var user1 = new User { Name = "Peter", Age = 32 };
    context.Users.AddIfNotExists(user1, u => u.Name);

    var user2 = new User { Name = "Joe", Age = 25 };
    context.Users.AddIfNotExists(user2, u => u.Age);

    // Adds user1 if there is no user with name "Peter"
    // Adds user2 if there is no user with age 25
    context.SaveChanges();
}

So later it can be used like this:

之后它可以这样使用:

using (var cOntext= new MyDbContext())
{
    var user1 = new User { Name = "Peter", Age = 32 };
    context.Users.AddIfNotExists(user1, u => u.Name);

    var user2 = new User { Name = "Joe", Age = 25 };
    context.Users.AddIfNotExists(user2, u => u.Age);

    // Adds user1 if there is no user with name "Peter"
    // Adds user2 if there is no user with age 25
    context.SaveChanges();
}

So later it can be used like this:

之后它可以这样使用:

using (var cOntext= new MyDbContext())
{
    var user1 = new User { Name = "Peter", Age = 32 };
    context.Users.AddIfNotExists(user1, u => u.Name);

    var user2 = new User { Name = "Joe", Age = 25 };
    context.Users.AddIfNotExists(user2, u => u.Age);

    // Adds user1 if there is no user with name "Peter"
    // Adds user2 if there is no user with age 25
    context.SaveChanges();
}

#5


1  

The only thing that comes to mind is to use IEqualityComparer, but this doesn't really stop the work, merely abstracts it away and creates cleaner code.

唯一想到的是使用IEqualityComparer,但这并不能真正停止工作,只是将它抽象出来并创建更简洁的代码。

#6


1  

What worked for me is this:

对我起作用的是:

public static void AddIfNotExists(this DbSet dbSet, Func predicate, params T [] entities) where T : class, new()
{
    foreach (var entity in entities)
    {
        var newValues = predicate.Invoke(entity);
        Expression> compare = arg => predicate(arg).Equals(newValues);
        var compiled = compare.Compile();
        var existing = dbSet.FirstOrDefault(compiled);
        if (existing == null)
        {
            dbSet.Add(entity);
        }
    }
}

推荐阅读
  • 深入解析 iOS Objective-C 中的对象内存对齐规则及其优化策略
    深入解析 iOS Objective-C 中的对象内存对齐规则及其优化策略 ... [详细]
  • 本文作为“实现简易版Spring系列”的第五篇,继前文深入探讨了Spring框架的核心技术之一——控制反转(IoC)之后,将重点转向另一个关键技术——面向切面编程(AOP)。对于使用Spring框架进行开发的开发者来说,AOP是一个不可或缺的概念。了解AOP的背景及其基本原理,对于掌握这一技术至关重要。本文将通过具体示例,详细解析AOP的实现机制,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 深入解析 Django 中用户模型的自定义方法与技巧 ... [详细]
  • 本文深入解析了 Apache 配置文件 `httpd.conf` 和 `.htaccess` 的优化方法,探讨了如何通过合理配置提升服务器性能和安全性。文章详细介绍了这两个文件的关键参数及其作用,并提供了实际应用中的最佳实践,帮助读者更好地理解和运用 Apache 配置。 ... [详细]
  • 在Unity中进行3D建模的全面指南,详细介绍了市场上三种主要的3D建模工具:Blender 3D、Maya和3ds Max。每种工具的特点、优势及其在Unity开发中的应用将被深入探讨,帮助开发者选择最适合自己的建模软件。 ... [详细]
  • C#编程指南:实现列表与WPF数据网格的高效绑定方法 ... [详细]
  • MongoDB Aggregates.group() 方法详解与编程实例 ... [详细]
  • MySQL:不仅仅是数据库那么简单
    MySQL不仅是一款高效、可靠的数据库管理系统,它还具备丰富的功能和扩展性,支持多种存储引擎,适用于各种应用场景。从简单的网站开发到复杂的企业级应用,MySQL都能提供强大的数据管理和优化能力,满足不同用户的需求。其开源特性也促进了社区的活跃发展,为技术进步提供了持续动力。 ... [详细]
  • 本文介绍了实现链表数据结构的方法与技巧,通过定义一个 `MyLinkedList` 类来管理链表节点。该类包含三个主要属性:`first` 用于指向链表的第一个节点,`last` 用于指向链表的最后一个节点,以及 `size` 用于记录链表中节点的数量。此外,还详细探讨了如何通过这些属性高效地进行链表的操作,如插入、删除和查找等。 ... [详细]
  • 深入解析JWT的实现与应用
    本文深入探讨了JSON Web Token (JWT) 的实现机制及其应用场景。JWT 是一种基于 RFC 7519 标准的开放性认证协议,用于在各方之间安全地传输信息。文章详细分析了 JWT 的结构、生成和验证过程,并讨论了其在现代 Web 应用中的实际应用案例,为开发者提供了全面的理解和实践指导。 ... [详细]
  • 本文深入探讨了 MXOTDLL.dll 在 C# 环境中的应用与优化策略。针对近期公司从某生物技术供应商采购的指纹识别设备,该设备提供的 DLL 文件是用 C 语言编写的。为了更好地集成到现有的 C# 系统中,我们对原生的 C 语言 DLL 进行了封装,并利用 C# 的互操作性功能实现了高效调用。此外,文章还详细分析了在实际应用中可能遇到的性能瓶颈,并提出了一系列优化措施,以确保系统的稳定性和高效运行。 ... [详细]
  • 从 Java 过渡到 Ruby,不仅是一次编程语言的转换,更是一段技术进阶的旅程。本文将深入探讨两种语言在语法、生态系统和开发模式上的差异,帮助开发者顺利实现转型,并在新的环境中高效地编写高质量代码。 ... [详细]
  • NVIDIA最新推出的Ampere架构标志着显卡技术的一次重大突破,不仅在性能上实现了显著提升,还在能效比方面进行了深度优化。该架构融合了创新设计与技术改进,为用户带来更加流畅的图形处理体验,同时降低了功耗,提升了计算效率。 ... [详细]
  • 深入解析 javax.faces.view.ViewDeclarationLanguageWrapper.getWrapped() 方法及其应用实例 ... [详细]
  • 掌握DSP必备的56个核心问题,我已经将其收藏以备不时之需! ... [详细]
author-avatar
Zhangjingy2502870421
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有