I'm trying to implement my own AddOrUpdate
since Entity Framework doesn't contain this function for now. (And I need it)
I know there are similar questions here, but either there's no answer or it was another problem.
So, I'm stuck when trying to implement the update-part. This is my code:
public static void AddOrUpdate<T>(this DbSet<T> @this, Func<T, object> parameter, params T[] entries) where T: class, IEntity
{
IEnumerable<object> keysExisting = @this.Select(parameter);
foreach (T entry in entries)
{
bool entryExistsAlready = keysExisting.Contains(parameter.Invoke(entry));
if (!entryExistsAlready)
{
@this.Add(entry);
return;
}
entry.Id = @this.First(w => parameter.Invoke(w).Equals(parameter.Invoke(entry))).Id;
@this.Attach(entry);
@this.Update(entry);
}
}
and for completing the information, this is how I call the method (There's already an ApplicationUser stored in the DB, with the Email "test@test.de"):
db.ApplicationUsers.AddOrUpdate(s => s.Email,
new ApplicationUser{Email="test@test.de", Attribute="modified attribute"}
);
I tried with attaching the entry and without attaching. I'm always getting following exception (either on Attach()
or, when don't attaching, on Update()
:
InvalidOperationException: The instance of entity type 'ApplicationUser' cannot be tracked because another instance of this type with the same key is already being tracked. When adding new entities, for most key types a unique temporary key value will be created if no key is set (i.e. if the key property is assigned the default value for its type). If you are explicitly setting key values for new entities, ensure they do not collide with existing entities or temporary values generated for other new entities. When attaching existing entities, ensure that only one entity instance with a given key value is attached to the context.
Any idea, how I can update my entries?
update:
I already tried with reflection, just setting all values from each property, but ApplicationUser e.g. has the property Role
which is not writeable. So I'd lose data from my method-call.
答案 0 :(得分:5)
使用约定,如果构成实体主键的所有属性都具有默认值(0,null等),那么该实体是新的,否则它已经存在:
public TEntity AddOrUpdate<TEntity>(DbContext context, TEntity entity)
where TEntity : class
{
context.Entry(entity).State =
context.KeyValuesFor(entity).All(IsDefaultValue)
? EntityState.Added
: EntityState.Modified;
return entity;
}
private static bool IsDefaultValue(object keyValue)
{
return keyValue == null
|| (keyValue.GetType().IsValueType
&& Equals(Activator.CreateInstance(keyValue.GetType()), keyValue));
}
参考:
https://blog.oneunicorn.com/2012/05/03/the-key-to-addorupdate/