【问题标题】:How to handle validation in WPF when binding to DbSet<T>.Local?绑定到 DbSet<T>.Local 时如何处理 WPF 中的验证?
【发布时间】:2013-08-02 13:28:25
【问题描述】:

DbSet&lt;T&gt;.Local 提供了一个ObservableCollection,您可以将其绑定到 WPF 控件。就我而言,我将其绑定到网格。

如果我使用视图模型,我会让它们实现 INotifyDataErrorInfoIDataErrorInfo,然后编写 Fluent Validation 验证器来处理验证。

但在这里我通过DbSet&lt;T&gt;.Local 绑定到模型。我应该如何处理验证?

我应该在我的模型上实现INotifyDataErrorInfoIDataErrorInfo 吗?

或者有其他选择吗?

【问题讨论】:

    标签: wpf entity-framework entity-framework-5 idataerrorinfo inotifydataerrorinfo


    【解决方案1】:

    如果您的应用程序是一个胖客户端,这意味着应用程序的所有层都在一台物理机器上,那么您应该在您的模型上实现IDataErrorInfo

    另一方面,如果您的应用程序是一个瘦多级应用程序,这意味着您的模型是在服务器上实现的,并且您正在使用 WPF 桌面应用程序与服务器端代码进行通信,那么您应该实现 INotifyDataErrorInfo .

    【讨论】:

    • 这是一个think-client。是否有任何不涉及在模型本身上实现任一接口的替代方案?
    • @cocowalla 好吧,因为您正在从本地缓存访问这些对象,我相信没有其他选择,并且这种方式验证逻辑将与模型类相关联,这被许多人认为是一种很好的做法开发人员,它们是接口,因此您仍然可以根据需要从其他基类派生。
    【解决方案2】:

    是的,我认为在 POCO 模型中实现 IValidatableObject 是有意义的。 你可能已经注意到public ObservableCollection&lt;TEntity&gt; Local { get; }

    有几种方法可以做到这一点。所以做一些功课。

    As some background , might be useful

    Then check this out

    所以我们知道 EF 有触发 Validations 的概念。

    Configuration.ValidateOnSaveEnabled = true; 
    

    EF 也会调用IEnumerable&lt;ValidationResult&gt; ValidateInstance();

    来自接口IValidatableObject

    如果你的实体 POCO 实现了IValidatableObject

    EF 将在 SAve 上触发验证。 您还可以在需要时轻松触发验证。

    这一切都与 UoW 概念巧妙地联系在一起。

     public IEnumerable<DbEntityValidationResult> GetDbValidationErrors() { return 
            Context.GetValidationErrors(); }   // Standard Context call get the problems
    

    可以使用 捕捉(异常前){.... var x = GetDbValidationErrors(); //....

    所以我认为你在正确的轨道上......

    编辑:添加 SAMPLE POCOBase 并演示触发器验证。

    public interface IFBaseObject : IValidatableObject {
        // a POCO object must implement the VALIDATE method from    IValidatableObject
        bool IsValidInstance();
        IEnumerable<ValidationResult> ValidateInstance();
    
    }
    
    public abstract class BaseObject : IFBaseObject {
    
         // .... base object stuff removed....
    
        /// <summary>
        /// Get called every a Validation is trigger on an object.  Here we return and Empty resultset to start with.
        /// If you override ALWAYS call Base first and Continue to add your own results as desired.
        /// Never fail to call base First !
        /// </summary>
        public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
            # region Sample implementation for a POCO thats needs validation
    
            /* Sample Implementation a sub type POCO might use.
             var validationResult = base.Validate(validationContext).ToList();  
    
             if (true) // the condition that leads to a validation error
             {
                 var memberList = new List<string> { "PropertyName" }; // the name of the offending property
                 var error = new ValidationResult("Error text goes here", memberList); // use teh textpool !!! no hardcoded texts
                 validationResult.Add(error);
             }
    
             return validationResult;
           */
    
            # endregion
    
            // now back in the base Class.
            var validationResult = new List<ValidationResult>();
            // hand back a list that is empty so errors if any can be added by SUBclasses
            // we can check any Poco that implements a certain interface centrally.  
            var thisIsKeyGuid = this as IFKeyGuid;
            if (thisIsKeyGuid != null) {
                if (thisIsKeyGuid.Id == Guid.Empty) {
                    validationResult.Add(new ValidationResult("Id is required", new List<string>() {"Id"}));
                }
            }
    
            return validationResult;
        }
    
        /// <summary>
        /// Allows explicit triggering of Validation and returns a TRUE or false answer. Call anytime
        /// </summary>
        /// <returns></returns>
        public virtual bool IsValidInstance() {
            List<ValidationResult> vResults;
            return SelfValidation(out vResults);
        }
    
        /// <summary>
        /// Calls Self Validation which uses THIS object as the context for validation.
        /// This means you can trigger a validation without first declaring a validation context.
        /// IValidatableObject is effectively called for you. Witch causes "Validate" to be called
        /// </summary>
        /// <returns></returns>
        public IEnumerable<ValidationResult> ValidateInstance() {
            List<ValidationResult> vResults;
            SelfValidation(out vResults);
            return vResults;
        }
    
        /// <summary>
        /// Although SelfValidation is defined at BaseObject level, this triggers the VALIDATION process on the current Object
        /// see http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.validator.aspx for mroe details
        /// So if a POCO Object has overridden  public virtual IEnumerable of ValidationResult Validate(ValidationContext validationContext) 
        /// then this method will be called.  It should of course call :base.Validate
        /// </summary>
        /// <returns>true or false</returns>
        private bool SelfValidation(out List<ValidationResult> vResults) {
            var vc = new ValidationContext(this, null, null);
            vResults = new List<ValidationResult>();
            var isValid = Validator.TryValidateObject(this, vc, vResults, true);
            return isValid;
        }
    }
    

    【讨论】:

    • WPF 是否支持 IValidateObject?
    • 不确定 WPF 是否直接调用验证。 MVC 和 EF 可以。但是正如这篇文章所展示的那样,任何钩子都可以触发调用。我将添加一个如何连接的示例......与此同时,这篇文章可能很有用stackoverflow.com/questions/7121867/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-18
    • 1970-01-01
    相关资源
    最近更新 更多