EF ValidationContext: 如何知道实体是被创建还是被更新

3
在MVC中为实体指定自定义验证方法时,我实现了接口。 现在,在验证代码中,如果该实体正在被创建,我希望执行某些操作,如果正在被更新,则执行其他的操作。以下示例展示了我想要的功能:
public partial class ActividadProyecto : IValidatableObject
    {

        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            if (IsBeingCreated)
            {
                // Do stuff
            }
            else if(IsBeingUpdated)
            {
                // Do other stuff
            }
        }
}

有没有可能实现?我搜索了很多,但都没有接近这个的。我找到的唯一解决方案是为创建流程和更新流程分别制作ViewModel,然后为它们各自制作独立的验证器:这太荒谬、太丑陋了。

提前感谢!


1
如果您将int/long作为表的主键,那么快速帮助是:如果Id>0,则更新否则插入。 - Monah
很遗憾,由于客户需求,必须使用GUID。谢谢。 - Felipe Correa
@HadiHassan 我最终采用了您的建议,使用GUID来验证并针对 Guid.Empty 进行检查以判断实体是正在被创建还是更新。我尝试了许多替代方案,但都没能达到我想要的效果。这个解决方案很简单,虽然我认为它可以做得更好,但至少在一段时间内它会让我感到满意。谢谢! - Felipe Correa
2个回答

4
通过在您的DbContext中覆盖ValidateEntity()方法,您可以通过validationContext.Items字典对象将所需信息传递给实体的Validate()方法。
public class YourDbContext : DbContext
{
    // other code

    protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
    {
        items["is_data_layer"] = true;
        items["is_insert"] = this.Entry(entityEntry.Entity).State == EntityState.Added;
        return base.ValidateEntity(entityEntry, items);
    }
}

从你的实体中使用:

public partial class ActividadProyecto : IValidatableObject
{
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        object dummy;

        // skip logic if "Validate" is not called from EF...
        if (validationContext.Items.TryGetValue("is_data_layer", out dummy))
        {
            if ((bool)validationContext.Items["is_insert"]) // insert mode
            {
                // Do stuff
            }
            else // update mode
            {
                // Do other stuff
            }
        }
    }
}

编辑:

我承认我的回答仅从 EF (数据层) 的角度回答。我不是 ASP.NET MVC 的专家。但正如 mo.esmp 指出的那样,如果您还将 EF 实体用作“视图模型”,则 MVC 框架也会调用 Validate() 方法来验证视图层中的实体。只有在此之后,EF 才会调用 Validate 方法。这解释了为什么您的实体的 Validate 方法在上下文的 ValidateEntity 方法之前被调用。

因此,问题变为:您对添加逻辑感兴趣的是哪个验证?您想要在“视图层”验证中添加逻辑吗?还是您想要在“数据层”(EF)验证期间应用您的逻辑?

我没有足够的细节来回答您的问题。但是,如果您只需要在“数据层”(EF)验证阶段添加逻辑,则我已经调整了上面的示例代码以跳过逻辑(如果验证不是由 EF 调用)。您可以尝试一下。


谢谢你的回答。不过我遇到了一个问题,由于某种原因,在 DbContext 的 ValidateEntity 方法之前调用了 Validate 方法 :-/ 有什么想法吗? - Felipe Correa
mo.esmp的评论对你观察到的情况提供了合理的解释。我调整了我的答案,希望能解决这个问题。但要看你是在“视图层”验证阶段还是“数据层”(EF)验证阶段添加逻辑。希望对你有所帮助。 - sstan
这可以像你说的那样完成,是一个很好的解决方案,但它增加了捕获DbValidationError异常并将错误发送到MVC视图的复杂性,所以我选择放弃这个选项。无论如何感谢您!我会将其标记为答案,因为如果您想深入了解并修复其他问题使其在MVC中工作,这确实有效。 - Felipe Correa

1
当你将表单提交到服务器时,ASP.NET MVC模型绑定器尝试将“Form”绑定到“ActividadProyecto”实体,同时执行“IValidatableObject.Validate”方法来验证你的模型。但是,当你尝试保存实体时,EF“ValidateEntity”方法将被执行。因此,在“IValidatableObject.Validate”方法中,你无法确定实体是创建还是更新,因为它发生在EF“ValidateEntity”方法之前。

感谢您对验证行为的澄清。只是想澄清一下,正如@sstan所指出的那样,可以通过一些额外的代码来完成。 - Felipe Correa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接