gpt4 book ai didi

c# - 在对象图中查找具有相同键的实体以防止 "An object with the same key already exists in the ObjectStateManager"错误

转载 作者:太空狗 更新时间:2023-10-29 23:00:41 25 4
gpt4 key购买 nike

我首先使用 EF 代码来开发我的 3 层 WinForm 应用程序,我使用断开连接的 POCO 作为我的模型实体。我所有的实体都继承自 BaseEntity 类。

我使用了断开连接的 POCO,所以我在客户端处理实体的 State,在 ApplyChanges() 方法中,我附加了我的实体图(例如一个 Order 及其 OrderLinesProducts)到我的 DbContext 然后同步每个实体的 State 及其客户端 State

public class BaseEntity
{

int _dataBaseId = -1;

public virtual int DataBaseId // DataBaseId override in each entity to return it's key
{
get { return _dataBaseId; }
}

public States State { get; set; }

public enum States
{
Unchanged,
Added,
Modified,
Deleted
}
}

所以,当我想保存相关实体的图时,我使用了以下方法:

    public static EntityState ConvertState(BaseEntity.States state)
{
switch (state)
{
case BaseEntity.States.Added:
return EntityState.Added;
case BaseEntity.States.Modified:
return EntityState.Modified;
case BaseEntity.States.Deleted:
return EntityState.Deleted;
default:
return EntityState.Unchanged;
}
}

public void ApplyChanges<TEntity>(TEntity root) where TEntity : BaseEntity
{
_dbContext.Set<TEntity>().Add(root);
foreach (var entry in _dbContext.ChangeTracker
.Entries<BaseEntity>())
{
BaseEntity stateInfo = entry.Entity;
entry.State = ConvertState(stateInfo.State);
}
}

但是如果我的图表包含 2 个或更多具有相同键的实体,我会给出此错误:

An object with the same key already exists in the ObjectStateManager...

如何在我的图表 (root) 中检测具有相同键的实体,并使它们在我的 ApplyChanges() 方法中唯一?

最佳答案

有一种方法可以搜索数据库并检查是否已经存在具有相同主键的记录,我不知道那是不是你要找的,但代码如下:

public static class ObjectSetExtensions
{
#region Constants

private const BindingFlags KeyPropertyBindingFlags =
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

#endregion

#region Public Methods and Operators

public static bool RecordExists<TEntity>(
this ObjectSet<TEntity> set,
TEntity entity) where TEntity : class
{
Contract.Requires(set != null);
Contract.Requires(entity != null);

var expressionParameter = Expression.Parameter(typeof(TEntity));
var keyProperties = set.GetKeyProperties();

var matchExpression =
keyProperties.Select(
pi =>
Expression.Equal(
Expression.Property(expressionParameter, pi.Last()),
Expression.Constant(pi.Last().GetValue(entity, null))))
.Aggregate<BinaryExpression, Expression>(
null,
(current, predicate) => (current == null) ? predicate :
Expression.AndAlso(current, predicate));

var existing =
set.SingleOrDefault(Expression.Lambda<Func<TEntity, bool>>(
matchExpression,
new[] { expressionParameter }));

return existing != null;
}

#endregion

#region Methods

private static IEnumerable<PropertyPathCollection> GetKeyProperties<TEntity>(this ObjectSet<TEntity> objectSet)
where TEntity : class
{
Contract.Requires(objectSet != null);

var entityType = typeof(TEntity);

return
objectSet.EntitySet.ElementType.KeyMembers.Select(
c => new PropertyPathCollection(entityType.GetProperty(c.Name, KeyPropertyBindingFlags)));
}

#endregion
}

public sealed class PropertyPathCollection : IEnumerable<PropertyInfo>
{
// Fields
#region Static Fields

public static readonly PropertyPathCollection Empty = new PropertyPathCollection();

#endregion

#region Fields

private readonly List<PropertyInfo> components;

#endregion

// Methods
#region Constructors and Destructors

public PropertyPathCollection(IEnumerable<PropertyInfo> components)
{
this.components = new List<PropertyInfo>();
this.components.AddRange(components);
}

public PropertyPathCollection(PropertyInfo component)
{
this.components = new List<PropertyInfo> { component };
}

private PropertyPathCollection()
{
this.components = new List<PropertyInfo>();
}

#endregion

#region Public Properties

public int Count
{
get
{
return this.components.Count;
}
}

#endregion

#region Public Indexers

public PropertyInfo this[int index]
{
get
{
return this.components[index];
}
}

#endregion

#region Public Methods and Operators

public static bool Equals(PropertyPathCollection other)
{
if (ReferenceEquals(null, other))
{
return false;
}

return true;
}

public static bool operator ==(PropertyPathCollection left, PropertyPathCollection right)
{
return Equals(left, right);
}

public static bool operator !=(PropertyPathCollection left, PropertyPathCollection right)
{
return !Equals(left, right);
}

public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}

if (ReferenceEquals(this, obj))
{
return true;
}

if (obj.GetType() != typeof(PropertyPathCollection))
{
return false;
}

return Equals((PropertyPathCollection)obj);
}

public override int GetHashCode()
{
return this.components.Aggregate(0, (t, n) => (t + n.GetHashCode()));
}

#endregion

#region Explicit Interface Methods

IEnumerator<PropertyInfo> IEnumerable<PropertyInfo>.GetEnumerator()
{
return this.components.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return this.components.GetEnumerator();
}

#endregion
}

用法是这样的:

var context = this.DbContext;
var adapter = context as IObjectContextAdapter;
var objectContext = adapter.ObjectContext;

objectContext.CreateObjectSet<TEntity>().RecordExists(instance);

关于c# - 在对象图中查找具有相同键的实体以防止 "An object with the same key already exists in the ObjectStateManager"错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14138374/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com