Нарушение инварианта контракта кода в С# с использованием Entity Framework

Я новичок в EF и кодовом контракте, для выполнения проекта я использую EF6 и кодовый контракт.

Как вы знаете, в первом подходе к БД EF автоматически генерирует классы, соответствующие объектам БД, я добавил контракты к частичным классам, которые я определил вручную.

Сгенерированный EF класс:

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; }
}

и вручную определенный класс:

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);
        }
    }
}

Проблема, которая возникла при вызове метода этого класса в проекте, - это нарушение инварианта, по сути эта ошибка:

Ошибка инварианта: contentText != null

Теперь, это для наличия двух конструкторов?

И как я могу решить эту проблему?


person Meysam PH    schedule 25.12.2014    source источник
comment
Не по теме, но очень важно: не используйте такие конструкции типа активной записи. Article должен быть постоянно игнорируемым классом.   -  person Gert Arnold    schedule 26.12.2014
comment
для достижения стойких невежественных классов я не должен использовать EF! или?   -  person Meysam PH    schedule 26.12.2014
comment
Он имеет в виду сделать Article просто простым держателем значений и написать логику для извлечения/сохранения в другом классе (обычно DAO).   -  person SJuan76    schedule 26.12.2014
comment
Конечно, вы можете использовать EF. Но в EF есть парадигма репозитория/единицы работы, которая полностью отличается от активной записи. Я предлагаю вам взглянуть на некоторые примеры приложений, использующих EF, чтобы понять суть. Это слишком широкая тема для ответа. Но позвольте мне раскрыть одну вещь: EF предоставляет репозитории (DbSet) и UoW (DbContext) из коробки. Часто люди, начинающие работать с EF, слепо следуют этим проповедникам универсального репозитория. Будьте проще: простые сервисные методы работают с простыми POCO, используя контексты и DbSet.   -  person Gert Arnold    schedule 26.12.2014
comment
@ SJuan76 Нет. И не DAO. Все активные записи/DAO поощряют взаимодействие с одной базой данных для отдельных объектов. Они значительно усложняют работу с графами объектов по сравнению с EF.   -  person Gert Arnold    schedule 26.12.2014


Ответы (1)


Вы можете создать еще один класс для доступа к данным (с EF) в качестве репозитория и избежать подобных ошибок контракта; например:

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);
    }
}

из здесь

person Majid    schedule 27.12.2014