xling
xling

Reputation: 252

Entity Framework , how to only validate specify property

I have a demo class "User" like the following:

public partial class User {
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }

    [StringLength(30)]
    [Required]
    public string LoginName { get; set; }

    [StringLength(120)]
    [Required]
    [DataType(DataType.Password)]
    public string Pwd { get; set; }

    [StringLength(50)]
    public string Phone { get; set; }

    [StringLength(100)]
    public string WebSite { get; set; }

... ... }

As you can see, "LoginName" and "Pwd" are "Required".

Some time , I only want to update user's "WebSite" , So I do like this:

    public void UpdateUser(User user , params string[] properties) {
        this.rep.DB.Users.Attach(user);
        this.rep.DB.Configuration.ValidateOnSaveEnabled = false;
        var entry = this.rep.DB.Entry(user);
        foreach(var prop in properties) {
            var entProp = entry.Property(prop);
            //var vas = entProp.GetValidationErrors();
            entProp.IsModified = true;
        }
        this.rep.DB.SaveChanges();
        this.rep.DB.Configuration.ValidateOnSaveEnabled = true;
    }

Parameter "user" like this: new User(){ ID = 1, WebSite = "http://www.stackoverflow.com" }

Notice , I don't specify "LoginName" and "Pwd"

This function can work fine , but I wouldn't set ValidateOnSaveEnabled to false.

Is there any way only validate "WebSite" when ValidateOnSaveEnabled is true? Thanks.

Upvotes: 0

Views: 1623

Answers (2)

xling
xling

Reputation: 252

I get a solution. First define PartialValidationManager:

public class PartialValidationManager {

    private IDictionary<DbEntityEntry , string[]> dics = new Dictionary<DbEntityEntry , string[]>();

    public void Register(DbEntityEntry entry , string[] properties) {
        if(dics.ContainsKey(entry)) {
            dics[entry] = properties;
        } else {
            dics.Add(entry , properties);
        }
    }

    public void Remove(DbEntityEntry entry) {
        dics.Remove(entry);
    }

    public bool IsResponsibleFor(DbEntityEntry entry) {
        return dics.ContainsKey(entry);
    }

    public void ValidateEntity(DbEntityValidationResult result) {
        var entry = result.Entry;
        foreach(var prop in dics[entry]){
            var errs = entry.Property(prop).GetValidationErrors();
            foreach(var err in errs) {
                result.ValidationErrors.Add(err);
            }
        }
    }
}

2, Add this Manager to My DbContext:

public class XmjDB : DbContext {

    public Lazy<PartialValidationManager> PartialValidation = new Lazy<PartialValidationManager>();

    protected override System.Data.Entity.Validation.DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry , IDictionary<object , object> items) {
        if(this.PartialValidation.Value.IsResponsibleFor(entityEntry)) {
            var result = new DbEntityValidationResult(entityEntry , new List<DbValidationError>());
            this.PartialValidation.Value.ValidateEntity(result);
            return result;
        } else
            return base.ValidateEntity(entityEntry , items);
    }

... ...

Update Method :

    public void UpateSpecifyProperties(T t, params string[] properties) {
        this.DB.Set<T>().Attach(t);
        var entry = this.DB.Entry<T>(t);
        this.DB.PartialValidation.Value.Register(entry , properties);
        foreach(var prop in properties) {
            entry.Property(prop).IsModified = true;
        }
        this.DB.SaveChanges();
        this.DB.PartialValidation.Value.Remove(entry);
    }

Ok, it work fine.

Upvotes: 1

Ladislav Mrnka
Ladislav Mrnka

Reputation: 364279

As I know validation executed in SaveChanges always validates the whole entity. The trick to get selective validation for property is commented in your code but it is not part of the SaveChanges operation.

Upvotes: 1

Related Questions