Search code examples
c#entity-frameworkasp.net-mvc-5code-contractsobject-oriented-analysis

Code contract invariant violation in C# using Entity Framework


I'm beginner at EF and code contract, for doing a project I use the EF6 and code contract.

As you know in DB first approach, EF automatically generates classes corresponding to the DB entities, I added contracts to the partial classes which I defined manually.

EF generated class:

public partial class Article
{
    public Article()
    {
        this.Comment = new HashSet<Comment>();
    }

    public int articleId { get; set; }
    public string title { get; set; }
    public string contentText { get; set; }
    public System.DateTime creationDate { get; set; }
    public System.DateTime modificationDate { get; set; }
    public int numOfVisits { get; set; }
    public bool enabled { get; set; }
    public int creatorId { get; set; }
    public int categoryId { get; set; }
    public string img { get; set; }

    public virtual ICollection<Comment> Comment { get; set; }
    public virtual Category Category { get; set; }
    public virtual Administrator Administrator { get; set; }
}

and manually defined class:

public partial class Article
{
    [ContractInvariantMethod]
    private void ObjectInvariant()
    {
        Contract.Invariant(contentText != null);
    }

    public Article(string title, string img, int catid, string content)
    { 
        Contract.Ensures(this.title.Equals(title));
        Contract.Ensures(this.img.Equals(img));
        Contract.Ensures(categoryId.Equals(catid));
        Contract.Ensures(Enumerable.SequenceEqual(Contract.OldValue(content), content));
        this.title = title;
        this.img = img;
        categoryId = catid;
        contentText = content;
        creationDate = DateTime.Now;
        modificationDate = DateTime.Now;
        numOfVisits = 0;
        enabled = true;
        DBConnection.addObject<Article>(this);
    }

    public Article editArticle(int id,string title, string img, int catid, string content)
    {
        using (var c = new SabaDataEntity())
        {
            var art = c.Article.FirstOrDefault(i => i.articleId == id);

            if(art != null)
            {
                art.title = title;
                art.img = img;
                art.categoryId = catid;
                art.contentText = content;
            }

            c.SaveChanges();
            return art;
        }
    }

    public Article deleteById(int id)
    {
        using (var c = new SabaDataEntity())
        {
            var obj = c.Article.FirstOrDefault(i => i.articleId == id);

            if (obj != null)
            {
                c.Article.Remove(obj);
                c.SaveChanges();
                return obj;
            }

            return obj;
        }
    }

    public  List<Article> getAll()
    {
        using (var c = new SabaDataEntity())
        {
            return c.Article.ToList();
        }
    }

    public string getCategoryName()
    {
        using (var c = new SabaDataEntity())
        {
            var cat = c.Category.FirstOrDefault(i => i.categoryId == this.categoryId);

            if (cat != null)
                return cat.persianTitle;

            return "";
        }
    }

    public Article get(int id)
    {
        using (var c = new SabaDataEntity())
        {
           return c.Article.FirstOrDefault(i => i.articleId == id);
        }
    }
}

The problem which occurred when I calling a method of this class in the project is a violation of invariant, in fact this error :

Invariant failed: contentText != null

Now, is it for availability of two constructors?

And how can I solve this problem?


Solution

  • You can create another class for data access (with EF) as repository and avoid this sort of contract errors; e.g:

    public class GenericRepository<T>: IDisposable  where T : class
    {
        private SabaDataEntity db = null;
        private DbSet<T> table = null;
        static readonly GenericRepository<T> instance = new GenericRepository<T>();
        public static readonly GenericRepository<T> Instance
        {
            get
            {
                return instance;
            }
        }
    
        public GenericRepository()
        {
            this.db = new SabaDataEntity();
            table = db.Set<T>();
        }
    
        public List<T> getAll()
        {
            return table.ToList();
        }
    
        public T getById(int id)
        {
            return table.Find(id);
        }
    }
    

    from here