2017-05-07 80 views
1

我有一个模型,看起来像这样:如何抽象实体框架模特属性

public class Task : ITask 
{ 
    public int DocumentId { get; set; } 
    public virtual Document Document { get; set; } 
    public TaskType TaskType { get; } 
    public string Value { get; } 
} 

现在,这个类是直接在DbContext注册为DbSet。 这意味着Document属性必须是具体类型。我想让这个代码很容易测试,所以我希望将该属性作为接口,这是ITask接口所​​要求的。解决这个问题的一般方法是什么?

我想到的一种方法是将所有这些类放在单独的程序集中,但似乎有点不合适。

编辑:ITask接口在不同的组件中定义,因此它不应该知道Document类型。

+0

一个想法可以实现'Document:IDocument',将'ITask'定义为'ITask IDocument getDocumnet();并且最后提供一个实现:公共类任务:ITask { }公共虚拟文档文档{get;组; } public IDocument getDocumnet(){return this.Document; ' }'。但未经测试。 –

回答

1

接口可以在他们定义的属性,所以你ITask可以指定文件,如下所示:

public interface ITask { 
    Document Document { get; set; } 
} 

但你也说你想要的文件属性为一个接口,这将成为棘手的,因为你需要Task类中的具体类型。通用接口将在这里帮助。

// The interfaces 
public interface ITask<TDocument> where TDocument : IDocument, new() { 
    TDocument Document { get; set; } 
} 

public interface IDocument { 
    int Number { get; set; } // Example property 
} 


//The classes 
public class Document : IDocument{ 
    public int Number { get; set; } // Example property 
} 

public class Task : ITask<Document> { 
    public Document Document { get; set; } 
} 


// See if it works 
public class Test { 
    private Task myTask = new Task(); 

    public void TestMethod() { 
     myTask.Document.Number = 1; 
    } 
} 

请记住,在DBContext中使用具体类型。至于接口应该放在哪里,相同的组件或它们自己的位置,这里有不少观点。就我个人而言,我把它们放在自己的程序集中,远离实施类。这个问题值得一读: Should I have a separate assembly for interfaces?

还有一个评论,班级名称任务用于.Net线程库,所以也许值得考虑改变它,以避免可能的混淆。

+1

我总是觉得自己最终将项目的接口从实施中移出项目,所以最终我从一开始就把它们放入了自己的程序集中。 –

2

我只会将EF模型用于数据访问层,并为业务层创建单独的模型。数据访问层将负责将EF模型映射到业务层模型并将其交给业务层。

业务层模型也可以是不可变的,这可能有优势。您也可以要求所有属性为在您的构造函数中非空,您可以在整个业务层中依赖这个。

当然,你可以争辩说它的代码几乎是代码的两倍。这是真的,但海事组织导致更清洁的代码,因此这是我首选的方法。