当编辑页面中没有包含在MVC绑定中时,维护实体原始属性的最佳方法是什么?

时间:2011-11-16 01:45:58

标签: asp.net-mvc entity-framework ado.net

我有一个用于编辑模型对象的ASP.NET MVC视图。编辑页面包含我的对象的大部分属性,但不包括所有属性 - 特别是它不包括CreatedOn和CreatedBy字段,因为它们是在创建时设置的(在我的服务层中),并且将来不应更改。

除非我将这些属性作为隐藏字段包含在内,否则它们将不会在Binding期间被拾取,并且在我在EF 4 DB上下文中保存修改后的对象时不可用。实际上,在保存时,原始值将被空值覆盖(或某些特定于类型的默认值)。

我不想将它们放在隐藏字段中,因为它浪费了字节,我不希望这些值暴露于潜在的操作。

有没有“一流”的方式来处理这种情况?除非明确设置,否则是否可以指定忽略EF模型属性?

5 个答案:

答案 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