Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[EF / Web API / C#] Validatie start eind datum

Pagina: 1
Acties:

  • PdeBie
  • Registratie: Juni 2004
  • Laatst online: 10:14
Hoi allen,

wellicht simpele vraag:

Object X heeft meerdere properties, waaronder een start- en einddatum.

Hoe kan ik er in EF voor zorgen dat de property EndDate niet voor de BeginDate kan komen te liggen? Ik dacht wellicht dat ik de waarde van BeginDate in het Range attribuut van EndDate kon zetten, maar dit mag niet.

Ik kan natuurlijk in de POST functie hier wel een validatie voor bouwen, maar het lijkt me handiger dat EF dit zelf regelt middels de modelstate.

  • Viper®
  • Registratie: Februari 2001
  • Niet online
Je kan in EF hiervoor een custom validate maken

  • PdeBie
  • Registratie: Juni 2004
  • Laatst online: 10:14
ok, dus een eigen validatie attribuut bedoel je?

Ga ik daar eens op Googlen.

  • Viper®
  • Registratie: Februari 2001
  • Niet online
http://www.codeguru.com/c...-the-Entity-Framework.htm

stukje Doing Custom Validations

http://www.entityframewor...-in-entity-framework.aspx

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[ComplexType]
public class Translated : IValidatableObject
{
    public string NL { get; set; }

    public string EN { get; set; }

    [NotMapped]
    public string TranslatedText
    {
        get
        {
            return Util.Translate(NL, EN);
        }
    }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (!string.IsNullOrEmpty(NL) && string.IsNullOrEmpty(EN))
            yield return new ValidationResult("EN is required if NL is entered.");

        if (!string.IsNullOrEmpty(EN) && string.IsNullOrEmpty(NL))
            yield return new ValidationResult("NL is required if EN is entered.");
    }
}

[ Voor 58% gewijzigd door Viper® op 16-07-2014 16:54 ]


  • PdeBie
  • Registratie: Juni 2004
  • Laatst online: 10:14
In je voorbeeld linkjes gaat het om validatie die afgaat op het moment dat <DBContext>.SaveChanges() aangeroepen wordt. Dit is te laat. Wil het liefst bij de check ModelState.IsValid al zien dat hij invalid is.

Maar goed.... Custom validatie attribuut dus. Ik ga eens puzzelen. Bedankt voor de voorzet. :)

  • HMS
  • Registratie: Januari 2004
  • Laatst online: 17-11 00:33

HMS

Zou je ondertussen niet beter je validatie kunnen vervangen door iets als FluentValidation? Die kan ook makkelijk geïntegreerd worden in ASP.NET MVC (zijn hulp packages voor), zodat je nog steeds de ModelState blijft gebruiken.

  • PdeBie
  • Registratie: Juni 2004
  • Laatst online: 10:14
Zal er eens naar kijken. Alleen had ik deze customvalidator inmiddels al af :)

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/// <summary>
/// Validation attribute for measuring two properties where one property should be greater than another property
/// </summary>
/// <author>P. de Bie</author>
public class PropertyMustBeGreaterThanAttribute : ValidationAttribute
{
    private static readonly string MustBeGreaterThanErrorMessage = ValidationMessages.MustBeGreaterThan;
    private readonly string _unknownPropertyErrorMessage = GeneralMessages.UnknownProperty;
    private readonly string _incompatibleObjectTypeErrorMessage = GeneralMessages.IncompatibleType;

    private readonly string _testedPropertyName;
    private readonly bool _allowEqualDates;

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="testedPropertyName"></param>
    /// <param name="allowEqualDates"></param>
    public PropertyMustBeGreaterThanAttribute(string testedPropertyName, bool allowEqualDates = false)
        : base(MustBeGreaterThanErrorMessage)
    {
        _testedPropertyName = testedPropertyName;
        _allowEqualDates = allowEqualDates;
    }

    /// <summary>
    /// Determines whether the specified value of the object is valid.
    /// </summary>
    /// <param name="value">The value of the object to validate.</param>
    /// <param name="validationContext">Context where to retrieve property</param>
    /// <returns>true if the specified value is valid; otherwise, false.</returns>
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var propertyTestedInfo = validationContext.ObjectType.GetProperty(_testedPropertyName);
        if (propertyTestedInfo == null)
        {
            return new ValidationResult(String.Format(_unknownPropertyErrorMessage, _testedPropertyName));
        }

        var propertyTestedValue = propertyTestedInfo.GetValue(validationContext.ObjectInstance, null);

        if (!(value is DateTime))
        {
            return new ValidationResult(String.Format(_incompatibleObjectTypeErrorMessage, _testedPropertyName));
        }

        if (!(propertyTestedValue is DateTime))
        {
            return new ValidationResult(String.Format(_incompatibleObjectTypeErrorMessage, _testedPropertyName));
        }

        // Compare values of both objects
        if ((DateTime) value < (DateTime) propertyTestedValue)
        {
            return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
        }

        // Compare values of both objects
        if ((DateTime) value > (DateTime) propertyTestedValue)
        {
            return ValidationResult.Success;
        }

        // Values of both objects are the same. Is this allowed
        return _allowEqualDates
            ? ValidationResult.Success
            : new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
    }

    public override string FormatErrorMessage(string paramName)
    {
        return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
            paramName, _testedPropertyName);
    }
}


Te gebruiken door middel van:

C#:
1
2
3
4
5
6
[DataType(DataType.Date)]
public DateTime? BeginDate { get; set; }

[DataType(DataType.Date)]
[PropertyMustBeGreaterThanAttribute("BeginDate", true)]
public DateTime? EndDate { get;set; } 


Nu nog een keer kijken om deze validator zo te maken dat het niet alleen voor DateTime objecten werkt, maar ook voor typen als Integers, Decimals etc.

[ Voor 6% gewijzigd door PdeBie op 17-07-2014 12:09 ]


  • sig69
  • Registratie: Mei 2002
  • Laatst online: 02:31
Dat is toch niet zo moeilijk? Pak in plaats van DateTime gewoon IComparable.

Roomba E5 te koop


  • PdeBie
  • Registratie: Juni 2004
  • Laatst online: 10:14
sig69 schreef op donderdag 17 juli 2014 @ 12:43:
Dat is toch niet zo moeilijk? Pak in plaats van DateTime gewoon IComparable.
Dat gaat bij de controle of het een geschikt objecttype is goed, maar niet bij de vergelijking of de waarde groter of kleiner is.

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//Dit gaat goed
if (!(value is IComparable))
{
    return new ValidationResult(String.Format(_incompatibleObjectTypeErrorMessage, _testedPropertyName));
}

if (!(propertyTestedValue is IComparable))
{
    return new ValidationResult(String.Format(_incompatibleObjectTypeErrorMessage, _testedPropertyName));
}

//Hieronder gaat het mis.
//Operator > cannot be applied to operands of type object and object

// Compare values of both objects
if (value < propertyTestedValue)
{
    return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}

// Compare values of both objects
if (value > propertyTestedValue)
{
    return ValidationResult.Success;
}


value en propertyTestedValue moet ik ergens naar casten. Maar ja... hoe weet ik nou wat voor type het zijn? :)

[ Voor 5% gewijzigd door PdeBie op 17-07-2014 13:35 ]


  • Viper®
  • Registratie: Februari 2001
  • Niet online
Type opvragen en vergelijken in een switch

code:
1
2
3
4
5
6
7
8
9
10
switch (Type.GetTypeCode(value.GetType()))
{
    case TypeCode.Decimal:
        // validatie decimal cast etc.
        break;

    case TypeCode.DateTime:
        // validatie datetime cast etc.
        break;
}


werkt alleen met primitieve types.

Meer info: http://blogs.msdn.com/b/j...6/switching-on-types.aspx

[ Voor 22% gewijzigd door Viper® op 17-07-2014 13:54 ]


  • PdeBie
  • Registratie: Juni 2004
  • Laatst online: 10:14
top! dank je wel. Dan ga ik er wel uit komen :)

  • sig69
  • Registratie: Mei 2002
  • Laatst online: 02:31
value en propertyTestedValue moet ik ergens naar casten. Maar ja... hoe weet ik nou wat voor type het zijn?
Dat boeit toch niet? Als ze maar:
• Van hetzelfde type zijn
• IComparable implementeren
Viper® schreef op donderdag 17 juli 2014 @ 13:44:
Type opvragen en vergelijken in een switch

code:
1
2
3
4
5
6
7
8
9
10
switch (Type.GetTypeCode(value.GetType()))
{
    case TypeCode.Decimal:
        // validatie decimal cast etc.
        break;

    case TypeCode.DateTime:
        // validatie datetime cast etc.
        break;
}


werkt alleen met primitieve types.

Meer info: http://blogs.msdn.com/b/j...6/switching-on-types.aspx
Dat is echt ranzig en niet onderhoudbaar. Je kan toch gewoon MSDN: IComparable.CompareTo Method (System) gebruiken, ben je in een keer klaar voor alle comparable types.

[ Voor 12% gewijzigd door sig69 op 17-07-2014 14:24 ]

Roomba E5 te koop


  • PdeBie
  • Registratie: Juni 2004
  • Laatst online: 10:14
sig69 schreef op donderdag 17 juli 2014 @ 14:20:
[...]
Dat is echt ranzig en niet onderhoudbaar. Je kan toch gewoon MSDN: IComparable.CompareTo Method (System) gebruiken, ben je in een keer klaar voor alle comparable types.
Klopt, zo heb ik het nu ook gedaan :)

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/// <summary>
/// Determines whether the specified value of the object is valid.
/// </summary>
/// <param name="value">The value of the object to validate.</param>
/// <param name="validationContext">Context where to retrieve property</param>
/// <returns>true if the specified value is valid; otherwise, false.</returns>
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
    var propertyTestedInfo = validationContext.ObjectType.GetProperty(_testedPropertyName);
    if (propertyTestedInfo == null)
    {
        return new ValidationResult(String.Format(_unknownPropertyErrorMessage, _testedPropertyName));
    }

    var propertyTestedValue = propertyTestedInfo.GetValue(validationContext.ObjectInstance, null);

    if (!(value is IComparable))
    {
        return new ValidationResult(String.Format(_incompatibleObjectTypeErrorMessage, _testedPropertyName));
    }

    if (!(propertyTestedValue is IComparable))
    {
        return new ValidationResult(String.Format(_incompatibleObjectTypeErrorMessage, _testedPropertyName));
    }

    var isGreaterThan = GreaterThan(value, propertyTestedValue);
    var isLessThan = LessThan(value, propertyTestedValue);

    if (isLessThan)
    {
        return ValidationResult.Success;
    }

    if (isGreaterThan)
    {
        return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
    }

    // Values of both objects are the same. Is this allowed?
    return _allowEqualValues
        ? ValidationResult.Success
        : new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}

public override string FormatErrorMessage(string paramName)
{
    return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
        paramName, _testedPropertyName);
}

private static bool GreaterThan(object x, object y)
{
    return CompareObjectValues(x, y) > 0;
}

private static bool LessThan(object x, object y)
{
    return CompareObjectValues(x, y) < 0;
}

private static bool ObjectEquals(object x, object y)
{
    return CompareObjectValues(x, y) == 0;
}

/// <summary>
/// Compares the current instance (x) with another object (y) of the same type. 
/// </summary>
/// <remarks>
/// ((IComparable)(x)).CompareTo(y)
/// A 32-bit signed integer that indicates the relative order of the comparands. The return value has one of the three meanings described in the following table.
/// </remarks>
/// <param name="x">current instance</param>
/// <param name="y">another object of the same type</param>
/// <returns>
/// Less than 0 (zero) > This object (x) is less than object (y)
/// 0 (zero) > This object (x) is equal to object (y)
/// Greater than 0 (zero) > This object (x) is greater than object (y)
/// </returns>
private static int CompareObjectValues(object x, object y)
{
    return ((IComparable) (x)).CompareTo(y);
}

  • sig69
  • Registratie: Mei 2002
  • Laatst online: 02:31
Ik zie dat je een groot fan bent van veel code schrijven... Maar liefst vijf oneliner functies voor dit? Verder cast je een paar keer onnodig veel. En 13 regels commentaar boven een functie die alleen een compare doet, al een duidelijk naam heeft, en nog private is ook?
Ik zou er zoiets van gemaakt hebben denk ik:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
{ 
    var propertyTestedInfo = validationContext.ObjectType.GetProperty(_testedPropertyName); 
    if (propertyTestedInfo == null)  
        return new ValidationResult(String.Format(_unknownPropertyErrorMessage, _testedPropertyName)); 
    
    var propertyTestedValue = propertyTestedInfo.GetValue(validationContext.ObjectInstance, null); 

    var v1 = value as IComparable;
    var v2 = value as IComparable;
    if(v1 == null || v2 == null)
        return new ValidationResult(String.Format(_incompatibleObjectTypeErrorMessage, _testedPropertyName)); 
    
    var result = v1.CompareTo(v2);
    
    if (result > 0) 
        return ValidationResult.Success; 

    if (result < 0) 
        return new ValidationResult(String.Format(CultureInfo.CurrentUICulture, ErrorMessageString, paramName, _testedPropertyName)); 

    return _allowEqualValues 
        ? ValidationResult.Success 
        : new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); 
} 

Roomba E5 te koop


  • PdeBie
  • Registratie: Juni 2004
  • Laatst online: 10:14
Ik snap dat het wellicht eenvoudiger kan, maar dit is een eerste attribuut die ik nu gemaakt heb, namelijk het 'GreaterThan'-attribuut. Er zal waarschijnlijk ook nog een 'LessThan'-attribuut gemaakt moeten worden. Dus die one-liner functies zijn er vooral voor dat ik die daar makkelijk in kan hergebruiken.

Dat commentaar is een kopie van de tekst van MSDN, maar ik vond het wel even makkelijk om het erbij te houden, omdat ik de CompareTo functie nog niet ken. Zo onthoud ik het beter. :)
Puur iets wat ik mezelf aangeleerd heb.

Natuurlijk had ik dit

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
private static bool GreaterThan(object x, object y) 
{ 
    return CompareObjectValues(x, y) > 0; 
} 

private static bool LessThan(object x, object y) 
{ 
    return CompareObjectValues(x, y) < 0; 
} 

private static bool ObjectEquals(object x, object y) 
{ 
    return CompareObjectValues(x, y) == 0; 
} 

/// <summary> 
/// Compares the current instance (x) with another object (y) of the same type.  
/// </summary> 
/// <remarks> 
/// ((IComparable)(x)).CompareTo(y) 
/// A 32-bit signed integer that indicates the relative order of the comparands. The return value has one of the three meanings described in the following table. 
/// </remarks> 
/// <param name="x">current instance</param> 
/// <param name="y">another object of the same type</param> 
/// <returns> 
/// Less than 0 (zero) > This object (x) is less than object (y) 
/// 0 (zero) > This object (x) is equal to object (y) 
/// Greater than 0 (zero) > This object (x) is greater than object (y) 
/// </returns> 
private static int CompareObjectValues(object x, object y) 
{ 
    return ((IComparable) (x)).CompareTo(y); 
}


ook zo kunnen schrijven:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private static bool GreaterThan(object x, object y) 
{ 
    return ((IComparable) (x)).CompareTo(y) > 0; 
} 

private static bool LessThan(object x, object y) 
{ 
    return ((IComparable) (x)).CompareTo(y) < 0; 
} 

private static bool ObjectEquals(object x, object y) 
{ 
    return ((IComparable) (x)).CompareTo(y) == 0; 
} 


maar dan is voor mij niet meteen duidelijk wat ((IComparable) (x)).CompareTo(y) doet. Daarom dat ik dat naar een nieuwe functie heb gezet met daarbij het commentaar wat kleiner dan 0, gelijk aan 0 en groter dan 0 betekend.

[ Voor 62% gewijzigd door PdeBie op 17-07-2014 15:51 ]

Pagina: 1