Entity Framework UI Validation using WinForms - c#

I'm interested in setting up client side validation using a WinForms application and Entity Framework 5. I understand that there's the IValidatableObject interface that I can implement to perform and custom validation that I may need for each entity.
However, since I'm using WinForms I'd like to use the ErrorProvider to present the user with a nice notification when there is a validation error as they fill out a form. Is this functionality able to be achieved using the IValidatableObject interface or would I need to implement the IDataErrorInfo interface on my entities as well in order to have the ErrorProvider work properly?
If you have any other suggestions on a better alternative to this please let me know and I'll gladly look into that as well.

Lets say you have an Entity called Car and this class contains an property which need be validated.
public class Car
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
// Accepted values have to be between 1 and 5.
public int NeedToBeValidatedRange { get; set; }
}
You have to create a base class for all your entites in my example I will called Entity.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
/// This is the base class for all entities and it provide a change notfication.
public abstract class Entity : INotifyPropertyChanged
{
// Event fired when the property is changed!
public event PropertyChangedEventHandler PropertyChanged;
/// Called when int property in the inherited class is changed for ther others properties like (double, long, or other entities etc,) You have to do it.
protected void HandlePropertyChange(ref int value, int newValue, string propertyName)
{
if (value != newValue)
{
value = newValue;
this.Validate(propertyName);
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
/// Validate the property
/// <returns>
/// The list of validation errors
/// </returns>
private ICollection<ValidationResult> PropertyValidator(string propertyName)
{
var validationResults = new Collection<ValidationResult>();
PropertyDescriptor property = TypeDescriptor.GetProperties(this)[propertyName];
Validator.TryValidateProperty(
property.GetValue(this),
new ValidationContext(this, null, null) { MemberName = propertyName },
validationResults);
return validationResults;
}
/// Validates the given property and return all found validation errors.
private void Validate(string propName)
{
var validationResults = this.PropertyValidator(propName);
if (validationResults.Count > 0)
{
var validationExceptions = validationResults.Select(validationResult => new ValidationException(validationResult.ErrorMessage));
var aggregateException = new AggregateException(validationExceptions);
throw aggregateException;
}
}
}
Now you shall modfiy the Car class and it should be like that:
public class Car : Entity
{
private int id;
private int needToBeValidatedRange;
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id
{
get
{
return this.id;
}
set
{
this.HandlePropertyChange(ref this.id, value, "Id");
}
}
[Range(1, 5)]
public int NeedToBeValidatedRange
{
get
{
return this.needToBeValidatedRange;
}
set
{
this.HandlePropertyChange(ref this.needToBeValidatedRange, value, "NeedToBeValidatedRange ");
}
}
}
Somewhere in the user interface you are creating the car entities:
Car car1 = new Car();
car1.NeedToBeValidatedRange = 3; // This will work!
Car car2 = new Car();
car2.NeedToBeValidatedRange = 6; // This will throw ValidationException
WPF support very good ValidationException.
Winforms support partially ValidationException but now you are free how to handle this.

There are two choices:
extend your poco classes with IValidateObject and IdataErrorInfo and raise the ui error in the validation method.
catch the validation error when save changes is called and invoke ErrorProvider directly depending on which entity field generates the validation error.
See the following for examples of extending poco classes with IValidateObject and handling validation errors when save changes are called.
http://msdn.microsoft.com/en-us/data/gg193959.aspx

Related

Entity Framework Core - Setting Value Converter generically

I'm currently trialing Entity Framework Core 2.1 with a view to using it in the company I work for's business applications. I've got most of the way in implementing Value Converters in my test project but my existing knowledge base has let me down at the last hurdle!
What I'm trying to do
My understanding is that for enum values, the built in type converters can convert from the enum value to the string equivalent (EnumToStringConverter) or from the enum value to it's numerical representation (EnumToNumberConverter). However we use a custom string value to represent the enum in our database, so I have written a custom EnumToDbStringEquivalentConvertor to do this conversion and the database string value is specified as an attribute on each of the enum values in my model.
The code is as follows:
Model
public class User
{
[Key] public int ID { get; set; }
public EmployeeType EmployeeType { get; set; }
}
public enum EmployeeType
{
[EnumDbStringValue("D")]
Director,
[EnumDbStringValue("W")]
Weekly,
[EnumDbStringValue("S")]
Salaried
}
DataContext
public class MyDataContext : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
foreach (var property in entityType.GetProperties())
{
if (property.ClrType.IsEnum)
{
property.SetValueConverter(new EnumToDbStringEquivalentConvertor<EmployeeType>());
}
}
}
}
}
Value Converter
public class EnumToDbStringEquivalentConvertor<T> : ValueConverter<T, string>
{
public EnumToDbStringEquivalentConvertor(ConverterMappingHints mappingHints = null) : base(convertToProviderExpression, convertFromProviderExpression, mappingHints)
{ }
private static Expression<Func<T, string>> convertToProviderExpression = x => ToDbString(x);
private static Expression<Func<string, T>> convertFromProviderExpression = x => ToEnum<T>(x);
public static string ToDbString<TEnum>(TEnum tEnum)
{
var enumType = tEnum.GetType();
var enumTypeMemberInfo = enumType.GetMember(tEnum.ToString());
EnumDbStringValueAttribute enumDbStringValueAttribute = (EnumDbStringValueAttribute)enumTypeMemberInfo[0]
.GetCustomAttributes(typeof(EnumDbStringValueAttribute), false)
.FirstOrDefault();
return enumDbStringValueAttribute.StringValue;
}
public static TEnum ToEnum<TEnum>(string stringValue)
{
// Code not included for brevity
}
}
This code (I'm glad to say) seems to be working without any issues.
My problem
The documentation around value converters seems to suggest the way we assign them in the OnModelCreating method is to physically assign each individual type converter to each individual property in the model. I don't want to have to do this - I want my model to be the driver. I'll implement this later but, for now, in the current version of the code I'm looping through the entity types in my model, checking the 'IsEnum' property value and then assigning the value converter at that point.
My problem is that the SetValueConverter extension method that I'm using requires me to pass it a new instance of EnumToDbStringEquivalentConvertor, which in my example is hard coded to be EnumToDbStringEquivalentConvertor which works. However I don't want that to be hardcoded - I want to pass the entity type's ClrType.
I have used reflection to create generic types and generic methods before but I can't seem to find the right code to get this working.
This:
public class MyDataContext : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
foreach (var property in entityType.GetProperties())
{
if (property.ClrType.IsEnum)
{
var converterType = typeof(EnumToDbStringEquivalentConvertor<>);
var genericConverterType = converterType.MakeGenericType(property.ClrType);
MethodInfo setValueConverterMethodInfo = typeof(MutablePropertyExtensions).GetMethod("SetValueConverter");
setValueConverterMethodInfo.Invoke(property,
new object[] { property, Activator.CreateInstance(genericConverterType) });
}
}
}
}
}
gives me an error of "System.MissingMethodException: 'No parameterless constructor defined for this object.'" on the GetModel method in Microsoft.EntityFrameworkCore.Infrastructure
So my question is can anyone advise me of how I can pass my value converter generically to EF Core's 'SetValueConveter' method?
Thank you in advance for your assistance.
You are almost there. The problem is this code
Activator.CreateInstance(genericConverterType)
which tries to find and invoke parameterless constructor of your converter class. But your class constructor does have a parameter, although optional. Optional parameters are just compiler sugar; when using reflection you should pass them explicitly.
So you need to use the CreateInstance overload accepting params object[] args and pass null for mappingHints.
Also, there is no need to call SetValueConverter via reflection - it's part of the public API.
The working code could be like this:
if (property.ClrType.IsEnum)
{
var converterType = typeof(EnumToDbStringEquivalentConvertor<>)
.MakeGenericType(property.ClrType);
var converter = (ValueConverter)Activator.CreateInstance(converterType, (object)null);
property.SetValueConverter(converter);
}

ScriptIgnore tag being ignored even with ApplyToOverrides = true... and it works in LinqPad

Basically, I'm trying to send a simple entity into json using JavaScriptSerializer. Yes, I know you want me to make a redundant class for that and shove it through AutoMapper and I'm asking for trouble. Humour me.
I'm using Entity Framework 6 to fetch a simple object to fetch a simple object.
Here's my test code:
[TestMethod]
public void TestEntityTest()
{
var db = new TestDbContext();
var ent = db.ResupplyForms.SingleOrDefault(e => e.Guid == new Guid("55117161-F3FA-4291-8E9B-A67F3B416097"));
var json = new JavaScriptSerializer().Serialize(ent);
}
Pretty straight forward. Fetch the thing and serialize it.
It errors out with the following:
An exception of type 'System.InvalidOperationException' occurred in System.Web.Extensions.dll but was not handled in user code
Additional information: A circular reference was detected while serializing an object of type 'System.Data.Entity.DynamicProxies.ResupplyForm_13763C1B587B4145B35C75CE2D5394EBED19F93943F42503204F91E0B9B4294D'.
Here's the entity:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Runtime.Serialization;
using System.Xml.Serialization;
using System.Data.Entity.Spatial;
using Rome.Model.DataDictionary;
using System.Web.Script.Serialization;
namespace Rome.Model.Form
{
[Table(nameof(ResupplyForm))]
public partial class ResupplyForm
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ResupplyFormID {get;set;}
public Guid Guid {get;set;}
public int? RecordStatus {get;set;}
[ForeignKey(nameof(RecordStatus))]
[ScriptIgnore(ApplyToOverrides = true)]
public virtual LookupItem RecordStatusLookupItem {get;set;}
}
}
I'll leave out the def for LookupItem because that gets into the schema of the whole rest of my project and there's no sane world in which that should matter, since I already flagged it as "ignored".
And here's a super-simple context:
public class TestDbContext : DbContext
{
public TestDbContext()
: base("data source=.;initial catalog=studybaseline;integrated security=True;pooling=False;multipleactiveresultsets=False")
{
}
public virtual DbSet<ResupplyForm> ResupplyForms { get; set; }
}
And now, the coup de gras: A LinqPad query that runs perfectly, using the exact same code as my snippet:
var db = new Rome.Model.Form.TestDbContext();
var ent = db.ResupplyForms.SingleOrDefault(e => e.Guid == new Guid("55117161-F3FA-4291-8E9B-A67F3B416097"));
var json = new JavaScriptSerializer().Serialize(ent).Dump();
Which happily returns
{"ResupplyFormID":1,"Guid":"55117161-f3fa-4291-8e9b-a67f3b416097","RecordStatus":null}
I have been pulling my hair out all day on this one, so any help is appreciated.
Okay, I've dug further into this a day later and found the cause: it has nothing to do with the [ScriptIgnore(ApplyToOverrides = true)] things. It has to do with the EntityProxy subclass that Entity Framework creates for every entity. My ResupplyForm isn't actually used as a ResupplyForm in my tests... instead it's an EntityProxy subclass.
This EntityProxy subclass adds a new member, _entityWrapper. If the EntityProxy is wrapping a class with no navigational properties, _entityWrapper doesn't contain any cycles... but as soon as you add a navigational property, the _entityWrapper contains cycles, which breaks serialization.
Vague error messages ruin everything. If the JavaScriptSerializer told me which field was bad, I could've saved a lot of time.
Anyhow, I should look at switching to NewtonSoft, but that's created its own problems (for another post) but instead I've created a very crude workaround:
public static class JsonSerializerExtensions
{
/// <summary>
/// Convert entity to JSON without blowing up on cyclic reference.
/// </summary>
/// <param name="target">The object to serialize</param>
/// <param name="entityTypes">Any entity-framework-related types that might be involved in this serialization. If null, it will only use the type of "target".</param>
/// <param name="ignoreNulls">Whether nulls should be serialized or not.</param>
/// <returns>Json</returns>
/// <remarks>This requires some explanation: all POCOs used by entites aren't their true form.
/// They're subclassed proxies of the object you *think* you're defining. These add a new member
/// _EntityWrapper, which contains cyclic references that break the javascript serializer.
/// This is Json Serializer function that skips _EntityWrapper for any type in the entityTypes list.
/// If you've a complicated result object that *contains* entities, forward-declare them with entityTypes.
/// If you're just serializing one object, you can omit entityTypes.
///</remarks>
public static string ToJsonString(this object target, IEnumerable<Type> entityTypes = null, bool ignoreNulls = true)
{
var javaScriptSerializer = new JavaScriptSerializer();
if(entityTypes == null)
{
entityTypes = new[] { target.GetType() };
}
javaScriptSerializer.RegisterConverters(new[] { new EntityProxyConverter(entityTypes, ignoreNulls) });
return javaScriptSerializer.Serialize(target);
}
}
public class EntityProxyConverter : JavaScriptConverter
{
IEnumerable<Type> _EntityTypes = null;
bool _IgnoreNulls;
public EntityProxyConverter(IEnumerable<Type> entityTypes, bool ignoreNulls = true) : base()
{
_EntityTypes = entityTypes;
_IgnoreNulls = ignoreNulls;
}
public override IEnumerable<Type> SupportedTypes
{
get
{
return _EntityTypes;
}
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
var result = new Dictionary<string, object>();
if (obj == null)
{
return result;
}
var properties = obj.GetType().GetProperties(
System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.GetProperty
);
foreach (var propertyInfo in properties.Where(p => Attribute.GetCustomAttributes(p, typeof(ScriptIgnoreAttribute), true).Length == 0))
{
if (!propertyInfo.Name.StartsWith("_"))
{
var value = propertyInfo.GetValue(obj, null);
if (value != null || !_IgnoreNulls)
{
result.Add(propertyInfo.Name, propertyInfo.GetValue(obj, null));
}
}
}
return result;
}
}
You have to pass in the classes (which, let's remember, are on-the-fly generated proxy classes) to use it, sadly, so it will probably fail miserably for any reasonable object-graph, but it will work for simple single objects and arrays and the like. It also fails for use with JsonResult because these overrides can't be used there.

How do I create multiple overloads of CRUD methods? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
If I have a class which represent a mapping to a specific table in my db in somehow.
This class contains about 30 properties.
I have created the CRUD Methods.
And find myself need to another (UPDATE) method which should update just two fields.
What should I do in a good manner with simple example?
Using my exist method, Filling the whole object and update all the fields including my intended two fields? (Useless work)
Create static Method with another name (but I want to keep my method name because it's expressive)! And takes two parameters?
I would go by by creating two separate interface and create overloaded functions for each interface. I would group properties based on usage, like I want status to be updated some time separate from other common properties.
public interface ICommonProperties
{
public string P1{get; set;}
public string P2{get; set;}
public string P3{ get; set; }
}
public interface ITrackable
{
public string Status{get; set;}
}
public class FinalClass : ICommonProperties, ITrackable
{
public string P1{get; set;}
public string P2{get; set;}
public string P3{get; set;}
public string Status{get; set;}
}
public class FinalClassOperations
{
public void Update(FinalClass finalClassInstance) { }; //Updates everything
public void Update(ICommonProperties finalClassInstance) { }; //Updates only ICommonProperties
public void Update(ITrackable finalClassInstance) { }; //updates only Status.
}
Additionally, if you want you can create a separate class for just updating the status, and that would still fit in:
public class Tracker : ITrackable{
public string Status{get; set;}
}
But yes, if the two properties cannot be separated out logically, I would not do that and keep them together.
I would suggest to follow your second option but there is no need to change the name as the number of method parameter will be different on both it's
Let's as walk into few example
I will try to create an similar situation, I hope it's your situation. you can clarify if i got wrongly the question.
CLASSES AND METHOD
/// <summary>
/// CLass to store properties related to database
/// </summary>
class ObjectoA
{
public string A{get; set;}
public string B{get; set;}
public string C{ get; set; }
}
/// <summary>
/// class to call method to update.
///
/// </summary>
class ObjectB
{
/// <summary>
/// update method.
/// I would go with this solution.
/// optionlay you can call the method which receive parameter of object
/// </summary>
/// <param name="A"> Object with properties mapped to database</param>
/// <param name="updatetwoproperties">Optional paramneter to decide which update to run.
/// the default value should be for update that run most. For your need if you want to create an update methods for other
/// two sets of parameter a suggest you create an Enum and pass this enum as optional parameter instead of bool parameter or you
/// can pass as string and map each string value to specific update inside. IF YOU NEED EXAMPLE
/// REPLAY ON COMMENTS</param>
/// <returns></returns>
public bool update(ObjectoA A, bool updatetwoproperties=false)
{
//method implementation
if (updatetwoproperties)
{
//implement a update to all field
}
else
{
//implement update just to two field
}
return true;
}
/// <summary>
/// update method based on parameter to update
/// </summary>
/// <param name="a">this properties is mapped on database</param>
/// <param name="b">this propertie is mapped on database</param>
/// <returns></returns>
public bool update(string a, string b)
{
//method implementation e validate the return value
return true;
}
}
/// <summary>
/// I don't suggest to use this solution because
/// it will add a method on string type while this method isn't related to string
/// I just added here as a workaround for you.
/// </summary>
public static class ObjectC
{
public static bool update(this string a, string b)
{
//implementation of update and validate the return value
return true;
}
}
CALLING METHOD AND EXPLANATION
static void Main(string[] args)
{
ObjectB B = new ObjectB(); //Class with methods
ObjectoA A = new ObjectoA(); //object with properties
#region Using Optional parameter to decide which update to run
//Calling a method to update all columns
B.update(A);
//Calling a method to update two columns
B.update(A, true);
#endregion
#region Using polymorphism to update
//Calling a method to update all columns
B.update(A);
//Update only using paramenter
B.update(A.B, A.C);
#endregion
//NOT RECOMMEND BECAUSE THIS UPDATE ISN'T RELATED TO STRING TYPE
#region Using extension method to update
//Calling a method to update all columns
B.update(A);
//using the extension method on variable type
A.B.update(A.C);
#endregion
//WE COULD USE EXTENSION METHOD ON YOUR OBJECT BUT IT WILL FAIL BECAUSE WE ALREADY AS UPDATE METHOD ON CLASS
//IF YOU WANT TO SEE HOW JUST REPLAY
}
I SUGGEST YOU ADD OPTIONAL PARAMETER ON YOUR METHOD TO DECIDE WHICH UPDATE TO USE
It depends on what your priorities are on the project:
using your already existing update method is gonna update everything all the time, incressing traffic, IO and process time (validation and so on...)
If you're on a project where properties are timestamped, they would be updated even if the value hasn't really changed...
If you don't mind about all this, use your update() method all the time.
My personnal POV is: create a new method (with an explicit name). This will same process time from now on and thinking time in 2 years when you'll have to change this class ;)
I don't know if this is what you should do necessarily, but here's something you could do: Create a SetAll or SetMany or whatever method where you pass in another instance of your class (source). Check each property and if it's non-null, you set the destination object's property value to the source object's property value. Note that this tactic will depend on nullable types, and assumes you can ignore null values passed into a new setter method. Here's an illustration:
using System;
namespace BlogPartialUpdateTrick
{
public class SomeClass
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int? HeightInches { get; set; }
public DateTime? Dob { get; set; }
public void SetAll(SomeClass source)
{
this.FirstName = source.FirstName ?? this.FirstName;
this.LastName = source.LastName ?? this.LastName;
this.HeightInches = source.HeightInches ?? this.HeightInches;
this.Dob = source.Dob ?? this.Dob;
}
public override string ToString()
{
return String.Format("fn: {0}, ln: {1}, height: {2}, DOB: {3}", FirstName ?? String.Empty, LastName ?? String.Empty,
HeightInches.HasValue ? HeightInches.Value.ToString() : "null", Dob.HasValue ? Dob.Value.ToShortDateString() : "null" );
}
}
}
In this first code sample, We have my spiffy class SomeClass. It's got 4 properties, all of which are nullable. The noteworthy part of this class is the SetAllMethod where I can pass in a source object which is also of type SomeClass. It sets this instance's property values to the values passed in the source parameter, but only if they're non-null. Here's a 2nd code blurb where I'm using this stuff:
using System;
using System.Windows.Forms;
namespace BlogPartialUpdateTrick
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var destination = new SomeClass() { FirstName = "Freddy", LastName = "Fingers", Dob = DateTime.Parse("01/01/1970"), HeightInches = 72 };
var source = new SomeClass() { FirstName = null, LastName="Flippers", Dob = null, HeightInches = 80 };
destination.SetAll(source);
MessageBox.Show(destination.ToString());
}
}
}
Create a destination object, a source object, call the new method, voila! output is this:
"fn: Freddy, ln: Flippers, height: 80, DOB: 1/1/1970"
You should probably use Entity Framework and let the context do it for you. Using EF, you'll be able to update Entities like this :
try
{
var original = ObjectContext.Set<Request>().SingleOrDefault(x => x.Id.Equals(_request.Id));
if (original != null)
{
ObjectContext.Entry(original).CurrentValues.SetValues(_request);
}
return ObjectContext.SaveChanges();
}
catch (Exception ee)
{
return -1;
}

IDataErrorInfo calling bound object rather than DataContext

I have a model:
public class Product
{
public int Rating { get; set; }
...
}
and a View Model:
public class ProductViewModel: IDataErrorProvider
{
public int Temperature { get; set; }
public Product CurrentProduct { get; set; }
public string this[string columnName]
{
get
{
if (columnName == "Rating")
{
if (CurrentProduct.Rating > Temperature)
return "Rating is too high for current temperature";
}
return null;
}
}
}
My view has an instance of ProductViewModel as the DataContext. The view has the field:
<TextBox Text={Binding Path=CurrentProduct.Rating, ValidatesOnDataErrors=True} .../>
By default, validation occurs on the IDataErrorProvider of the bound object (Product), not the DataContext (ProductViewModel). So in the above instance, ProductViewModel validation is never called. This is just a simple example but illustrates the problem. The model doesn't (and shouldn't) know about Temperature, so the design dictates that the VM should perform the validation on that field.
Yes, I could hack it and replicate the bound properties of the model directly in the ViewModel, but I would have thought there must be an easier way to redirect the call to the VM rather than the model?
If you want your viewmodel to validate a property named "Rating" by IDataErrorInfo, then your viewmodel must actually have a property called Rating and you must bind to it, which would mean to replicate the bound properties of the model in the viewmodel.
Anyway this blog article could be interesting for you (Validating Business Rules in MVVM). The author adds a Validation delegate to the model that the viewmodel can set. This allows you to validate your model using data that it does not known, like the Temperature in your example.
I've encountered that problem before, and my solution is to expose a validation delegate from my Models which is checked when validating the class, and the ViewModel can use this to hook addition validation to the class that is unrelated to Model itself
For example, I would use code that looked something like this from the ViewModel to attach a validation delegate to the Model anytime its set
public class ProductViewModel
{
public int Temperature { get; set; }
private product _currentProduct;
public Product CurrentProduct
{
get { return _currentProduct; }
set
{
if (value != _currentProduct)
{
if (_currentProduct != null)
_currentProduct.RemoveValidationDelegate(ValidateProduct);
_currentProduct = value;
if (_currentProduct != null)
_currentProduct.AddValidationDelegate(ValidateProduct);
RaisePropertyChanged("CurrentProduct");
}
}
}
// Product Validation Delegate to verify temperature
private string ValidateProduct(object sender, string propertyName)
{
if (propertyName == "Rating")
{
if (CurrentProduct.Rating > Temperature)
return "Rating is too high for current temperature";
}
return null;
}
}
The actual code that adds the ValidationDelegate to the Model is pretty generic, so I typically have it in a BaseViewModel so all Models can have this functionality without me having to type it out for each one
#region IDataErrorInfo & Validation Members
#region Validation Delegate
public delegate string ValidationDelegate(
object sender, string propertyName);
private List<ValidationDelegate> _validationDelegates = new List<ValidationDelegate>();
public void AddValidationDelegate(ValidationDelegate func)
{
_validationDelegates.Add(func);
}
public void RemoveValidationDelegate(ValidationDelegate func)
{
if (_validationDelegates.Contains(func))
_validationDelegates.Remove(func);
}
#endregion // Validation Delegate
#region IDataErrorInfo for binding errors
string IDataErrorInfo.Error { get { return null; } }
string IDataErrorInfo.this[string propertyName]
{
get { return this.GetValidationError(propertyName); }
}
public string GetValidationError(string propertyName)
{
string s = null;
foreach (var func in _validationDelegates)
{
s = func(this, propertyName);
if (s != null)
return s;
}
return s;
}
#endregion // IDataErrorInfo for binding errors
#endregion // IDataErrorInfo & Validation Members
I also have this approach outlined in my blog post here if you want to see another example.

Map a Dictionary in Entity Framework Code First Approach

I have a dictionary like this:
/// <summary>
/// Gets the leave entitlement details.
/// </summary>
/// <value>The leave entitlement details.</value>
public Dictionary<string, EmployeeLeaveEntitlement> LeaveEntitlementDetails { get; set; }
And I want to map it to the database. Is it possible to use a protected or private List<> for that? such as:
/// <summary>
/// Gets the leave entitlement details.
/// </summary>
/// <value>The leave entitlement details.</value>
public Dictionary<string, EmployeeLeaveEntitlement> LeaveEntitlementDetails { get; set; }
public List<EmployeeLeaveEntitlement> LeveEntitlementStore
{
get
{
List<EmployeeLeaveEntitlement> leaveEntitlements = new List<EmployeeLeaveEntitlement>();
foreach (KeyValuePair<string, EmployeeLeaveEntitlement> leaveType in LeaveEntitlementDetails)
{
leaveEntitlements.Add(leaveType.Value);
}
return leaveEntitlements;
}
set
{
foreach (EmployeeLeaveEntitlement item in value)
{
this.LeaveEntitlementDetails.Add(item.LeaveType, item);
}
}
}
Can anyone help me?
Entity Framework does not presently support mapping a Dictionary natively.
See the following for more information and work-arounds:
Entity Framework 4 POCO with Dictionary
EF Code First - Map Dictionary or custom type as an nvarchar
http://social.msdn.microsoft.com/Forums/en-US/adonetefx/thread/a51ba903-2b8b-448e-8677-d140a0b43e89/
EF Core 2.1 introduced a new feature called value conversion:
Value converters allow property values to be converted when reading from or writing to the database.
This feature highly simplifies the serialization approach mentioned in previous answers, which means, the introduction of on an additional "helper" property and the marking of your dictionary property as [NotMapped] becomes unnecessary.
Here are some lines of code tailored to your case (note, I am using Json.NET, but feel free to use your serializer of choice):
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace My.Name.Space
{
public class MyEntity
{
public int Id { get; set; }
public Dictionary<string, EmployeeLeaveEntitlement> LeaveEntitlementDetails { get; set; }
}
public class MyEntityConfiguration : IEntityTypeConfiguration<MyEntity>
{
public void Configure(EntityTypeBuilder<MyEntity> builder)
{
builder.ToTable("MyEntity");
builder.HasKey(e => e.Id);
builder
.Property(e => e.LeaveEntitlementDetails)
.IsRequired()
.HasConversion(
v => JsonConvert.SerializeObject(v),
v => v == null
? new Dictionary<string, EmployeeLeaveEntitlement>() // fallback
: JsonConvert.DeserializeObject<Dictionary<string, EmployeeLeaveEntitlement>>(v)
);
}
}
}
Using a XML Column in DB
So today I came across the same problem, and after thinking about it I found a cool solution which I would like to share with the community even if I am late.
Basically I've made a wrapping system which saves the data in the Dictionary to the Database as XML Column, so later I can also query the XML from the DB if I want.
Pro of this approach
Easy to use
Fast implementation
You can use the dictionary
You can query the XML column
First of all here's the bone of all my models:
public abstract class BaseEntity
{
/// <summary>
/// ID of the model
/// </summary>
public int ID { get; set; }
}
Suppose I have a model which contain a Dictionary<string,string> and a String property which contains the logic to Serialize and Deserialize the dictionary in XML, like the following snippet:
public class MyCoolModel : Base.BaseEntity
{
/// <summary>
/// Contains XML data of the attributes
/// </summary>
public string AttributesData
{
get
{
var xElem = new XElement(
"items",
Attributes.Select(x => new XElement("item", new XAttribute("key", x.Key), new XAttribute("value", x.Value)))
);
return xElem.ToString();
}
set
{
var xElem = XElement.Parse(value);
var dict = xElem.Descendants("item")
.ToDictionary(
x => (string)x.Attribute("key"),
x => (string)x.Attribute("value"));
Attributes = dict;
}
}
//Some other stuff
/// <summary>
/// Some cool description
/// </summary>
[NotMapped]
public Dictionary<string, string> Attributes { get; set; }
}
Then I've implemented a BaseMapping class which ineherits from EntityTypeConfiguration<T>
class BaseMapping<TEntity> : EntityTypeConfiguration<TEntity>
where TEntity : Model.Base.BaseEntity
{
public BaseMapping()
{
//Some basic mapping logic which I want to implement to all my models
}
}
And after a Custom Mapping for MyCoolModel
class MyCoolModelMapping
: BaseMapping<Model.MyCoolModel>
{
public MyCoolModelMapping()
{
Property(r => r.AttributesData).HasColumnType("xml");
}
}
Now notice that when AttributesData value is requested by EntityFramework it just serialize the dictionary and the same happens when I retrive data from the DB and EntityFramework sets the data to the field, which then
deserializes the object and sets it to the dict.
And finally I have override the OnModelCreating of my DbContext
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new Mappings.BaseMapping<SomeOtherModel>());
modelBuilder.Configurations.Add(new Mappings.MyCoolModelMapping());
//Other logic
}
And that's it! Now I can use the dictionary from my business logic and this "wrapping" handles all the stuff need to save the data to the DB and retrive the data from it.
I had a similar problem with EF were I wanted to convert a query returned list, into a class property's dictionary equivalent. Very similar to how you want to have LeaveEntitlementDetails wrapped by LeveEntitlementStore
For example:
class A
{
[NotMapped()]
public Dictionary<int, DataType> Data {get; set}
//refers to Data.Values
public ICollection<DataType> DataAsList {get; set}
}
Where I wanted DataAsList to essentially wrap Data.Values
After a lot of trial and error, I discovered that EF, for collections (maybe more) alters through the getter's returned value (rather than the setter).
I.e. when initializing from my db:
var pollquery=From bb In DBM.Dbi.DataTable.Includes("DataAsList")
Where bb.Id = id
Select bb;
ClassA objInstance = pollquery.First();
ClassA.DataAsList's setter was never being called, but the getter was during EF's internal construction of my object.... Conclusion: EF is using a reference retrieved from the getter of property ClassA.DataAsList, and adding objects to it.
So I wrapped my getter's return value for DataAsList in an ObservableCollection and added a handler for CollectionChanged args and sure enough, my handler for CollectionChanged was picking up .Add calls.
So heres my hackaround-workaround:
class A : INotifyPropertyChanged
{
//So we can let EF know a complex property has changed
public event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged;
//here's our actual data, rather than an auto property, we use an explicit member definition so we can call PropertyChanged when Data is changed
private Dictionary<int, DataType> m_data = new Dictionary<int, DataType>();
//not mapped property as it's not mapped to a column in EF DB
[NotMapped()]
public Dictionary<int, DataType> Data {
get { return m_data; }
set {
m_data = value;
//now call PropertyChanged for our Front (so EF will know it's been changed)
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs("DataAsList"));
}
}
}
//this is our front for the data, that we use in EF to map data to
[DebuggerHidden()]
public ICollection<DataType> DataAsList {
get {
ObservableCollection<DataType> ob = new ObservableCollection<DataType>(Data.Values());
ob.CollectionChanged += Handles_entryListChanged;
return ob;
}
set {
//clear any existing data, as EF is trying to set the collections value
Data.Clear();
//this is how, in my circumstance, i converted my object into the dictionary from an internal obj.Id property'
foreach (DataType entry in value) {
entryions.Add(entry.id, entry);
}
}
}
//This will now catch wind of any changes EF tries to make to our DataAsList property
public void Handles_entryListChanged(object sender, NotifyCollectionChangedEventArgs e)
{
//Debugger.Break()
switch (e.Action) {
case NotifyCollectionChangedAction.Add:
foreach (DataType entry in e.NewItems) {
m_data.Add(entry.Id, entry);
}
break;
default:
Debugger.Break();
break;
}
}
}
Note the Magic is the:
public ICollection<DataType> DataAsList {
get {
ObservableCollection<DataType> ob = new ObservableCollection<DataType>(Data.Values());
ob.CollectionChanged += Handles_entryListChanged;
return ob;
}
where we subscribe to any changes made to the returned list and Handles_entryListChanged where we handle and essentially replicate any changes made.
As mentioned in here, One important thing after object serialization, is that when updating the entity and changing items in the dictionary, the EF change tracking does not pick up on the fact that the dictionary was updated, so you will need to explicitly call the Update method on the DbSet<> to set the entity to modify in the change tracker.
there is also another good sample here

Categories