【问题标题】:How to check if two entity entries of a collection are the same如何检查集合的两个实体条目是否相同
【发布时间】:2015-06-06 18:17:02
【问题描述】:

我正在尝试一种通用方法来更新实体框架集合,一对多。我做了这个方法,但是当我尝试验证新集合中的元素是否已经存在于旧集合中时,我遇到了问题。如果存在,我必须更新它,而不是删除并重新添加它。

代码是这样的:

public TEntity UpdateCollection<TEntity, TChildren>(myappContext dbContext, TEntity parentObject, Expression<Func<TEntity, 
            ICollection<TChildren>>> propertyExpression, ICollection<TChildren> objectChilren) where TEntity : class where TChildren : class
        {

            var parentEntityObject = dbContext.Entry<TEntity>(parentObject);
            List<TChildren> originalChildrenData = parentEntityObject.Collection(propertyExpression).CurrentValue.ToList();

            // Updating or removing existing items
            foreach (var originalItem in originalChildrenData)
            {
                // Where the problem is: If entry was just modified, i have to update.
                var newItem = objectChilren.FirstOrDefault(x => x == originalItem);
                if (newItem != null)
                {
                    dbContext.Entry<TChildren>(originalItem).CurrentValues.SetValues(newItem);
                    dbContext.Entry<TChildren>(originalItem).State = System.Data.EntityState.Modified;
                }
                else
                {
                    dbContext.Entry<TChildren>(originalItem).State = System.Data.EntityState.Deleted;
                }
            }

            // Adding new items
            foreach(var newItem in objectChilren.Except(originalChildrenData)){
                parentEntityObject.Collection(propertyExpression).CurrentValue.Add(newItem);
            }

            parentEntityObject.State = System.Data.EntityState.Modified;
            return parentEntityObject.Entity;
        }

而不是尝试检查:

var newItem = objectChilren.FirstOrDefault(x => x == originalItem);
                    if (newItem != null)

我也试过:

var newItem = this.Set<TChildren>().Local.FirstOrDefault(x => x == originalItem);

但也不行,总是返回null。我必须得到相应的条目并且只更新它。

如果不可能,还有另一种通用方法来“一对多”更新集合吗?

【问题讨论】:

  • 尝试比较对象的主键属性,而不是我假设不会覆盖 Equals 和 GetHashKey 的对象本身。
  • 我也是这么想的,但是怎么知道哪些是de键呢?并比较它们?它需要是通用的,所以我不能定义主键。我必须找到哪个是关键,然后比较
  • 谢谢你,我确实有这样的想法:stackoverflow.com/questions/7253943/…

标签: c# entity-framework asp.net-mvc-4


【解决方案1】:

我按照 Magnus 的建议比较了我收藏中的关键属性,如下所示:

public TEntity UpdateCollection<TEntity, TChildren>(myappContext dbContext, TEntity parentObject, Expression<Func<TEntity, 
            ICollection<TChildren>>> propertyExpression, ICollection<TChildren> objectChilren) where TEntity : class where TChildren : class
        {

            var parentEntityObject = dbContext.Entry<TEntity>(parentObject);
            List<TChildren> originalChildrenData = parentEntityObject.Collection(propertyExpression).CurrentValue.ToList();

            // Get key name
            var entityKeyName = GetKeyName(dbContext, originalChildrenData.Union(objectChilren).First());

            // Updating or removing existing items
            foreach (var originalItem in originalChildrenData)
            {

                var originalValueKey = originalItem.GetType().GetProperty(entityKeyName).GetValue(originalItem, null);
                var itemCompareExpression = GetCompareExpression<TChildren>(entityKeyName, originalValueKey);

                // If entry was just modified, i have to update.
                var newItem = objectChilren.FirstOrDefault(itemCompareExpression.Compile());
                if (newItem != null)
                {
                    dbContext.Entry<TChildren>(originalItem).CurrentValues.SetValues(newItem);
                    dbContext.Entry<TChildren>(originalItem).State = System.Data.EntityState.Modified;
                    // Remove item, because only 'new items' will be added after this loop
                    objectChilren.Remove(newItem);
                }
                else
                {
                    dbContext.Entry<TChildren>(originalItem).State = System.Data.EntityState.Deleted;
                }
            }

            // Adding new items
            foreach(var newItem in objectChilren)
            {
                parentEntityObject.Collection(propertyExpression).CurrentValue.Add(newItem);
            }

            parentEntityObject.State = System.Data.EntityState.Modified;
            return parentEntityObject.Entity;
        }

调用的方法:

public string GetKeyName<TEntity>(myappContext dbContext, TEntity entity) where TEntity : class
        {
            ObjectContext objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
            ObjectSet<TEntity> set = objectContext.CreateObjectSet<TEntity>();
            return set.EntitySet.ElementType.KeyMembers.FirstOrDefault().Name;
        }

        public Expression<Func<TEntity, bool>> GetCompareExpression<TEntity>(string keyName, object value) where TEntity : class
        {
            var parameter = Expression.Parameter(typeof(TEntity), "x");
            var property = Expression.Property(parameter, keyName);
            var method = property.Type.GetMethod("Equals", new[] { property.Type });
            var convertedValue = Convert.ChangeType(value, property.Type);
            var expression = Expression.Call(property, method, Expression.Constant(convertedValue));

            return Expression.Lambda<Func<TEntity, bool>>(expression, parameter);
        }

由于我所有的实体只有一个键,我只是在“GetKeyName”上使用了“First”,但如果需要,它会返回所有键。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-21
    • 2023-03-13
    相关资源
    最近更新 更多