Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#4.0

Entity Framework Code First

4.00/5 (2 votes)
26 May 2011CPOL 24.5K  
Unique constraints
I just wanted to share a little tip here.

So far, in Entity Framework CTP 5, I think RTW does not implement a Unique Constraint for a given column. This is a major issue, I think, as it should mirror database capabilities, but that's another story.

This is what I did in my current project. I created an attribute where you can list the name of the fields that need to be flagged as Unique in your POCO, add this attribute to the POCO in question and finally implement a little check on the current object set against the new entity to be added.
The custom attribute looks like this:

C#
[System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple=false,Inherited=true)]
public class UniqueAttribute:System.Attribute
{
    private string[] _atts;
    public string[] KeyFields
    {
        get
        {
            return _atts;
        }
    }
    public UniqueAttribute(string keyFields)
    {
        this._atts = keyFields.Split(new char[]{','}, StringSplitOptions.RemoveEmptyEntries);
    }
}


Then, we implement it like this:

C#
[CustomAttributes.Unique("Name")]
public class Item: BasePOCO
{
    public string Name{get;set;}
    [StringLength(250)]
    public string Description { get; set; }
    [Required]
    public String Category { get; set; }
    [Required]
    public string UOM { get; set; }
}


Finally, I added this check on my Add method for my repository, we need to rely on reflection here of course, retrieving the values of the new entity and compare against the current set:
C#
private void ValidateDuplicatedKeys(T entity)
{
    var atts = typeof(T).GetCustomAttributes(typeof(UniqueAttribute), true);
    if (atts == null || atts.Skip(1).Any())
    {
        return;
    }
    foreach (var att in atts)
    {
        UniqueAttribute uniqueAtt = (UniqueAttribute)att;
        var newkeyValues = from pi in entity.GetType().GetProperties()
                            join k in uniqueAtt.KeyFields on pi.Name equals k
                            select new { KeyField = k, Value = pi.GetValue(entity, null).ToString() };
        foreach (var item in _objectSet)
        {
            var keyValues = from pi in item.GetType().GetProperties()
                            join k in uniqueAtt.KeyFields on pi.Name equals k
                            select new { KeyField = k, Value = pi.GetValue(item, null).ToString() };
            var exists = keyValues.SequenceEqual(newkeyValues);
            if (exists)
            {
                throw new System.Exception("Duplicated Entry found");
            }
        }
    }
}


Hope this gets you going and saves a little headache or 2 :D

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)