简体   繁体   English

EF生成的类和模型之间的关系?

[英]Relationship between EF-Generated classes and model?

I'm using ASP .NET MVC (C#) and EntityFramework (database first) for a project. 我正在为项目使用ASP .NET MVC(C#)和EntityFramework(首先是数据库)。

Let's say I'm on a "Movie detail" page which shows the detail of one movie of my database. 假设我在“电影详细信息”页面上,该页面显示了数据库中一部电影的详细信息。 I can click on each movie and edit each one. 我可以单击每部电影并进行编辑。 Therefore, I have a Movie class, and a Database.Movie class generated with EF. 因此,我有一个Movie类和一个用EF生成的Database.Movie类。

My index action looks like : 我的索引操作如下所示:

    public ActionResult MovieDetail(int id)
    {
        Movie movie = Movie.GetInstance(id);
        return View("MovieDetail", movie);    
    }

GetInstance method is supposed to return an instance of Movie class which looks like this for the moment : GetInstance方法应该返回Movie类的实例,该实例目前看起来像这样:

    public static Movie GetInstance(int dbId)
    {
        using (var db = new MoviesEntities())
        {
            Database.Movie dbObject = db.Movies.SingleOrDefault(r => r.Id == dbId);
            if (dbObject != null)
            {
                Movie m = new Movie(dbObject.Id, dbObject.Name, dbObject.Description);
                return m;
            }
            return null;
        }
    }

It works fine but is this a good way to implement it? 它工作正常,但这是实现它的好方法吗? Is there an other cleaner way to get my instance of Movie class ? 还有其他更干净的方法来获取Movie类的实例吗? Thanks 谢谢

is this a good way to implement it?

That's a very subjective question. 这是一个非常主观的问题。 It's valid, and there's nothing technically wrong with this implementation. 这是有效的,此实现在技术上没有任何错误。 For my small-size home projects, I've used similar things. 对于我的小型家庭项目,我使用了类似的东西。

But for business applications, it's better to keep your entities unrelated to your MVC application. 但是对于业务应用程序,最好使您的实体与MVC应用程序无关。 This means that your data context + EF + generated entities should be kept in a separate project (let's call it the 'Data' project), and the actual data is passed in the form of a DTO. 这意味着您的数据上下文+ EF +生成的实体应保存在单独的项目中(我们称其为“数据”项目),并且实际数据以DTO的形式传递。

So if your entity resembles this: 因此,如果您的实体类似于:

public class Person {
       public int Id { get; set; }
       public string Name { get; set; }
}

You'd expect there to be an equivalent DTO class that is able to pass that data: 您希望有一个等效的DTO类能够传递该数据:

public class PersonDTO {
       public int Id { get; set; }
       public string Name { get; set; }
}

This means that your 'Data' project only replies with DTO classes, not entities . 这意味着您的“数据”项目仅使用DTO类进行答复,而不使用Entity进行答复

public static MovieDTO GetInstance(int dbId)
{
    ...
}

It makes the most sense that your DTOs are also in a separate project. 最有意义的是,您的DTO也位于单独的项目中。 The reason for all this abstraction is that when you have to change your datacontext (eg the application will start using a different data source), you only need to make sure that the new data project also communicates with the same DTOs. 所有这种抽象的原因是,当您必须更改数据上下文 (例如,应用程序将开始使用其他数据源)时,只需确保新数据项目也与相同的DTO通信。 How it works internally, and which entities it uses, is only relevant inside the project. 它在内部的工作方式以及使用的实体仅与项目内部相关。 From the outside (eg from your MVC application), it doesn't matter how you get the data, only that you pass it in a form that your MVC projects already understand (the DTO classes). 从外部(例如,从你的MVC应用程序),也不要紧,你如何获取数据,只有你通过它在你的MVC项目已经明白(DTO的类)的形式。

All your MVC controller logic will not have to change, because the DTO objects haven't changed. 您的所有MVC控制器逻辑都不必更改,因为DTO对象没有更改。 This could save you hours. 这样可以节省您的时间。 If you link the entity to your Controller AND View, you'll have to rewrite both if you suddenly decide to change the entity. 如果将实体链接到Controller AND View,则突然决定更改实体时,必须重写两者。

If you're worried about the amount of code you'll have to write for converting entities to DTOs and vice versa, you can look into tools like Automapper . 如果您担心将实体转换为DTO以及反之亦然所需编写的代码量,可以考虑使用Automapper之类的工具。

The main question: Is this needed? 主要问题:这是否需要?

That, again, is a very subjective question. 同样,这是一个非常主观的问题。 It's relative to the scope of the project, but also the expected lifetime of the application. 它与项目范围有关,也与应用程序的预期寿命有关。 If it's supposed to be used for a long time, it might be worth it to keep everything interchangeable. 如果应该长期使用它,那么保持所有互换性可能是值得的。 If this is a small scale, short lifetime project, the added time to implement this might not be worth it. 如果这是一个规模小,寿命短的项目,那么增加执行此操作的时间可能不值得。

I can't give you a definitive answer on this. 我无法就此给出确切的答案。 Evaluate how well you want the application to adapt to changes, but also how likely it is that the applicaiton will change in the future. 评估您希望应用程序适应更改的程度,以及评估将来应用程序更改的可能性。

Disclaimer: This is how we do it at the company where I work. 免责声明:这就是我们在我工作的公司中所做的事情。 This is not the only solution to this type of problem, but it's the one I'm familiar with. 这不是解决此类问题的唯一解决方案,而是我所熟悉的解决方案。 Personally, I don't like making abstractions unless there's a functional reason for it. 就个人而言,除非有功能上的原因,否则我不喜欢进行抽象。

A few things: 一些东西:

  1. The naming you're using is a little awkward and confusing. 您使用的命名有点尴尬和混乱。 Generally, you don't ever want to have two classes in your project named the same, even if they're in different namespaces. 通常,您永远都不想在项目中拥有两个名称相同的类,即使它们位于不同的名称空间中也是如此。 There's nothing technically wrong with it, but it creates confusion. 从技术上讲,这没有什么错,但是会造成混乱。 Which Movie do I need here? 我需要哪部Movie And if I'm dealing with a Movie instance, is it Movie or Database.Movie ? 如果我要处理一个Movie实例,它是Movie还是Database.Movie If you stick to names like Movie and MovieDTO or Movie and MovieViewModel , the class names clearly indicate the purpose (lack of suffix indicates a database-backed entity). 如果您坚持使用MovieMovieDTOMovieMovieViewModel之类的名称,则类名将明确指示目的(后缀不足表示数据库支持的实体)。

  2. Especially if you're coming from another MVC framework like Rails or Django, ASP.NET's particular flavor of MVC can be a little disorienting. 特别是如果您来自另一个MVC框架(如Rails或Django),则ASP.NET独特的MVC风格可能会令人迷惑。 Most other MVC frameworks have a true Model, a single class that functions as the container for all the business logic and also acts as a repository (which could be considered business logic, in a sense). 大多数其他MVC框架都有一个真正的模型,一个单独的类,可以充当所有业务逻辑的容器,并且还可以充当存储库(在某种意义上可以视为业务逻辑)。 ASP.NET MVC doesn't work that way. ASP.NET MVC不能那样工作。 Your entities (classes that represent database tables) are and should be dumb. 您的实体(代表数据库表的类)是并且应该是哑巴的。 They're just a place for Entity Framework to stuff data it pulls from the database. 它们只是Entity Framework填充从数据库中提取的数据的地方。 Your Model (the M in MVC) is really more a combination of your view models and your service/DAL layer. 您的模型(MVC中的M)实际上更多是视图模型和服务/ DAL层的组合。 Your Movie class (not to be confused with Database.Movie ... see why that naming bit is important) on the other hand is trying to do triple duty, acting as the entity, view model and repository. 另一方面,您的Movie类(不要与Database.Movie混淆...请参阅该命名位为何很重要)正在尝试承担实体,视图模型和存储库的三重职责。 That's simply too much. 简直太过分了。 Your classes should do one thing and do it well. 您的课程应该做一件事并且做得很好。

  3. Again, if you have a class that's going to act as a service or repository, it should be an actual service or repository, with everything those patterns imply. 同样,如果您有一个将充当服务或存储库的类,则它应该是实际的服务或存储库,其中包含所有这些模式所暗示的内容。 Even then, you should not instantiate your context in a method. 即使那样,您也不应在方法中实例化上下文。 The easiest correct way to handle it is to simply have your context be a class instance variable. 最简单的正确处理方法是让您的上下文成为类实例变量。 Something like: 就像是:

     public class MovieRepository { private readonly MovieEntities context; public MovieRepository() { this.context = new MovieEntities(); } } 

    Even better, though is to use inversion of control and pass in the context: 更好的是,尽管使用控制反转并在上下文中传递:

     public class MovieRepository { private readonly MovieEntities context; public MovieRepository(MovieEntities context) { this.context = context; } } 

    Then, you can employ a dependency injection framework, like Ninject or Unity to satisfy the dependency for you (preferably with a request-scoped object) whenever you need an instance of MovieRepository . 然后,可以在需要MovieRepository的实例时采用Ninject或Unity之类的依赖项注入框架来满足您的依赖项(最好是使用请求范围的对象)。 That's a bit high-level if you're just starting out, though, so it's understandable if you hold off on going the whole mile for now. 但是,如果您刚刚起步的话,这有点高,所以如果您暂时不走一英里,那是可以理解的。 However, you should still design your classes with this in mind. 但是,您仍然应该牢记这一点来设计类。 The point of inversion of control is to abstract dependencies (things like the context for a class that needs to pull entities from the database), so that you can switch out these dependencies if the need should arise (say perhaps if there comes a time when you're going to retrieve the entities from an Web API instead of through Entity Framework, or even if you just decide to switch to a different ORM, such as NHibernate). 控制反转的目的是抽象依赖关系(诸如需要从数据库中提取实体的类的上下文之类的东西),以便您可以在需要时切换出这些依赖关系(例如,也许某个时候您将要从Web API检索实体,而不是通过Entity Framework检索实体,或者即使您只是决定切换到其他ORM(例如NHibernate)也是如此。 In your code's current iteration, you would have to touch every method (and make changes to your class in general, violating open-closed). 在代码的当前迭代中,您将必须触摸每个方法(并通常对类进行更改,这违反了开闭)。

entity-model never should act as view-model. 实体模型从不应该充当视图模型。 Offering data to the views is an essential role of the view-model. 向视图提供数据是视图模型的基本角色。 view-model can easily be recognized because it doesn't have any other role or responsibility other than holding data and business rules that act solely upon that data. 视图模型很容易识别,因为它除了拥有数据和仅对数据起作用的业务规则外,没有任何其他角色或职责。 It thus has all the advantages of any other pure model such as unit-testability. 因此,它具有任何其他纯模型的所有优点,例如单元可测试性。

A good explanation of this can be found in Dino Esposito's The Three Models of ASP.NET MVC Apps. 在Dino Esposito的ASP.NET MVC应用程序的三种模型中可以找到对此的很好解释

You can use AutoMapper 您可以使用AutoMapper

What is AutoMapper? 什么是AutoMapper?

AutoMapper is a simple little library built to solve a deceptively complex problem - getting rid of code that mapped one object to another. AutoMapper是一个简单的小库,旨在解决看似复杂的问题-摆脱将一个对象映射到另一个对象的代码。 This type of code is rather dreary and boring to write, so why not invent a tool to do it for us? 这种类型的代码相当沉闷且无聊,所以为什么不发明一种工具来为我们做呢?

How do I get started? 我该如何开始?

Check out the getting started guide . 查阅入门指南

Where can I get it? 我在哪里可以买到?

First, install NuGet. 首先,安装NuGet。 Then, install AutoMapper from the package manager console: 然后,从程序包管理器控制台安装AutoMapper:

PM> Install-Package AutoMapper

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 EF 生成的查询中应为“(” - Expected "(" on EF-generated query 如何检测 EF 生成的多对多自引用关系中的引用循环? - How can I detect reference loops in an EF-generated many-to-many self-reference relationship? 实体框架:使用接口扩展部分类而无需接触EF生成的类 - Entity Framework: Extending partial class with interface without touching the EF-generated classes EF生成的SQL和属性映射/投影 - EF-generated SQL and properties mapping/projection 在EF生成的类中返回单行,其子集在LinqToSql(c#)中排序 - Return single row in an EF-generated class with its children set ordered in LinqToSql (c#) 在生成的EF类中添加INotifyPropertyChange - Adding INotifyPropertyChange in generated EF classes EF生成的类和MVVM项目 - EF Generated Classes & MVVM Project EF代码中的模型n - n关系如何自动生成视图正常工作? - How Model n--n relationship in EF Code First to automatically generated views work correctly? EF模型优先的1:1关系问题 - 1:1 relationship problems with EF Model First 使用EF6和MVC4在域模型和SimpleMembership模型之间创建关系 - Create a relationship between domain model and SimpleMembership model using EF6 and MVC4
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM