我在数据层使用Repository包含chrisb建议的以下方法来更新实体,代码在更新之前首先访问主键:
var entry = _dbContext.Entry<T>(entity);
// Retreive the Id through reflection
var pkey = _dbset.Create().GetType().GetProperty("Id").GetValue(entity);
if (entry.State == EntityState.Detached)
{
var set = _dbContext.Set<T>();
T attachedEntity = set.Find(pkey); // You need to have access to key
if (attachedEntity != null)
{
var attachedEntry = _dbContext.Entry(attachedEntity);
attachedEntry.CurrentValues.SetValues(entity);
}
else
{
entry.State = EntityState.Modified; // This should attach entity
}
}
问题是如何将此方法与复合主键一起使用:即主键由两列或更多列组成时。
更新:我的问题在于Find()方法,例如当我将两个变量作为复合PK传递给它时,attachmentEntity为null,我得到了异常: “ObjectStateManager中已存在具有相同键的对象.ObjectStateManager无法使用相同的键跟踪多个对象。”
update2:这里是修改后的完整方法代码
public virtual void Update(T entity, params Object[] pkey)
{
var entry = _dbContext.Entry<T>(entity);
if (entry.State == EntityState.Detached)
{
var set = _dbContext.Set<T>();
T attachedEntity = set.Find(pkey); // You need to have access to key
if (attachedEntity != null)
{
var attachedEntry = _dbContext.Entry(attachedEntity);
attachedEntry.CurrentValues.SetValues(entity);
}
else
{
entry.State = EntityState.Modified; // This should attach entity
}
}
}
感谢。
答案 0 :(得分:1)
您可以将密钥传递到InsertOrUpdate
方法,而不是使用反射检索密钥:
public virtual T InsertOrUpdate(T e, params Object[] pkey)
{
//....
T attachedEntity = set.Find(pkey);
//...
}
如果您为主键传入了错误的值,则无法阻止将发生的错误。
获取泛型方法中密钥的另一种方法是创建一个抽象类,实体继承并约束存储库:
public class RepositoryBase<T> : IRepository<T> where T : ModelBase
{
public virtual T InsertOrUpdate(T e)
{
//....
T attachedEntity = set.Find(e.ID);
//...
}
}
public abstract class ModelBase
{
public int ID { get; set; }
}
参考: Repository pattern that allows for proxy creation
我更倾向于使用这种方法进行反射,因为它在编译时强制实施,但您必须对其进行调整以应对多个抽象类。 e.g。
public abstract class CompositeBase
{
public int Key1 {get; set:}
public int Key2 {get; set;}
}
public virtual T InsertOrUpdate(T e) where T: CompositeBase
{
//....
T attachedEntity = set.Find(e.Key1, e.Key2);
//...
}
或者,您可以调整以下代码以从元数据中检索KeyMembers(请参阅GetPrimaryKeyName
方法)
private static Dictionary<Type, EntitySetBase> _mappingCache =
new Dictionary<Type, EntitySetBase>();
private EntitySetBase GetEntitySet( Type type )
{
if ( !_mappingCache.ContainsKey( type ) )
{
ObjectContext octx = ( (IObjectContextAdapter)this ).ObjectContext;
string typeName = ObjectContext.GetObjectType( type ).Name;
var es = octx.MetadataWorkspace
.GetItemCollection( DataSpace.SSpace )
.GetItems<EntityContainer>()
.SelectMany( c => c.BaseEntitySets
.Where( e => e.Name == typeName ) )
.FirstOrDefault();
if ( es == null )
throw new ArgumentException( "Entity type not found in GetTableName", typeName );
_mappingCache.Add( type, es );
}
return _mappingCache[type];
}
private string GetTableName( Type type )
{
EntitySetBase es = GetEntitySet( type );
return string.Format( "[{0}].[{1}]",
es.MetadataProperties["Schema"].Value,
es.MetadataProperties["Table"].Value );
}
private string GetPrimaryKeyName( Type type )
{
EntitySetBase es = GetEntitySet( type );
return es.ElementType.KeyMembers[0].Name;
}
代码从Soft Delete pattern for Entity Framework Code First
解除其他参考资料:
答案 1 :(得分:0)
在实体构建器中
modelBuilder.Entity<T>()
.HasKey(o => new { key1, key2});
key1
和 key2
是复合键。