我有一个用于编辑模型对象的ASP.NET MVC视图。编辑页面包含我的对象的大部分属性,但不包括所有属性 - 特别是它不包括CreatedOn和CreatedBy字段,因为它们是在创建时设置的(在我的服务层中),并且将来不应更改。
除非我将这些属性作为隐藏字段包含在内,否则它们将不会在Binding期间被拾取,并且在我在EF 4 DB上下文中保存修改后的对象时不可用。实际上,在保存时,原始值将被空值覆盖(或某些特定于类型的默认值)。
我不想将它们放在隐藏字段中,因为它浪费了字节,我不希望这些值暴露于潜在的操作。
有没有“一流”的方式来处理这种情况?除非明确设置,否则是否可以指定忽略EF模型属性?
答案 0 :(得分:3)
使用:
public bool SaveRecording(Recording recording)
{
// Load only the DateTime property, not the full entity
DateTime oldCreatedOn = db.Recordings
.Where(r => r.Id == recording.Id)
.Select(r => r.CreatedOn)
.SingleOrDefault();
recording.CreatedOn = oldCreatedOn;
db.Entry(recording).State = EntityState.Modified;
db.SaveChanges();
return true;
}
(编辑:该查询仅从数据库加载CreatedOn
列,因此比加载完整实体更便宜,更快。因为您只需要CreatedOn
属性使用Find
将是不必要的开销:您加载所有属性,但只需要一个。此外,使用Find
加载完整实体然后之后使用AsNoTracking
分隔它可以是捷径:db.Recordings.AsNoTracking().SingleOrDefault(r => r.Id == recording.Id);
这会加载实体而不附加它,因此您不需要分离实体。使用AsNoTracking
可以更快地加载实体好。)
修改2
如果要从数据库加载多个属性,可以投影为匿名类型:
public bool SaveRecording(Recording recording)
{
// Load only the needed properties, not the full entity
var originalData = db.Recordings
.Where(r => r.Id == recording.Id)
.Select(r => new
{
CreatedOn = r.CreatedOn,
CreatedBy = r.CreatedBy
// perhaps more fields...
})
.SingleOrDefault();
recording.CreatedOn = originalData.CreatedOn;
recording.CreatedBy = originalData.CreatedBy;
// perhaps more...
db.Entry(recording).State = EntityState.Modified;
db.SaveChanges();
return true;
}
(编辑结束2)
或者:
public bool SaveRecording(Recording recording)
{
Recording oldVersion = db.Recordings.Find(recording.Id);
recording.CreatedOn = oldVersion.CreatedOn;
// flag only properties as modified which did really change
db.Entry(oldVersion).CurrentValues.SetValues(recording);
db.SaveChanges();
return true;
}
(编辑:仅使用CurrentValues.SetValues
标记为已修改的属性,与数据库中的原始状态相比确实已更改。当您调用SaveChanges
时,EF仅会发送在UPDATE语句中标记为已修改的属性到数据库。而将Modified
标记所有属性中的状态设置为已修改,无论它们是否真的发生了更改.UPDATE语句将是更昂贵,因为它包含所有列的更新。)
答案 1 :(得分:0)
如果您不想将该数据发送到客户端,我看不到任何其他选项,只是在您保存并合并这些原始属性值时从服务层中的db加载原始数据。到更新的对象。 EF无法知道您没有故意将这些值设置为null,并且实际上并不想以这种方式保存它们。
答案 2 :(得分:0)
您可以实现自己的模型绑定器,忽略您不想传递的属性。从这里开始 - http://lostechies.com/jimmybogard/2009/03/18/a-better-model-binder/
答案 3 :(得分:0)
我认为当您要更新时,请使用getById获取所有实体,然后设置相关属性,然后您可以更新。如果您使用某种映射器(Automapper)将视图模型中的属性映射到DB中的加载实体,那将很容易。
答案 4 :(得分:0)
如果您希望在每次更新之前避免对数据库进行额外(不必要的)调用,则可以使用self-tracking entities或将StoreGeneratedPattern="Identity"
设置为实体模型中的这些字段。是的,Identity
具有误导性,但这听起来像是你想要的设置:
标识在插入时生成一个值,并在更新时保持不变。
http://msdn.microsoft.com/en-us/library/system.data.metadata.edm.storegeneratedpattern.aspx