In a layered architecture using Entity Framework, should I return POCO classes from the BLL? (Architecture guidance needed)

后端 未结 3 2100
-上瘾入骨i
-上瘾入骨i 2021-02-09 02:36

I\'ve been reading too much probably and am suffering from some information overload. So I would appreciate some explicit guidance.

From what I\'ve gathered, I can use V

相关标签:
3条回答
  • 2021-02-09 03:11

    Answers to your questions may depend on the size and complexity of your application. So I am afraid there will be valid arguments to answer your questions with Yes and No as well.

    Personally I will answer your two main questions both with Yes:

    Is it acceptable practice to use POCO (Domain) classes in the UI layer?

    I guess with "UI layer" you don't actually mean the View part of the MVVM pattern but the ViewModels. (Most MVVM specialists would argue against letting a View directly reference the Model at all, I believe.)

    It is not unusual to wrap a POCO from your Domain project as a property into a ViewModel and to bind this wrapped POCO directly to the View. The big Pro is: It's easy. You don't need additional ViewModel classes or replicated properties in a ViewModel and then copy those properties between the objects.

    However, if you are using WPF you must take into account that the binding engine will directly write into your POCO properties if you bind them to a View. This might not always be what you want, especially if you are working with attached and change-tracked entities in a WPF form. You have to think about cancellation scenarios or how you restore properties after a cancellation which have been changed by the binding engine.

    In my current project I am working with detached entities: I load the POCO from the data layer, detach it from context, dispose the context and then work with that copy in the ViewModel and bind it to the View. Updating in the data layer happens by creating a new context, loading the original entity from the DB by ID and then updating the properties from the changed POCO which was bound to the View. So the problem of unwished changes of an attached entity disappears with this approach. But there are also downsides to work with detached entites (updating is more complex for instance).

    Is it okay if I implement the IDataErrorInfo interface on the generated POCO class?

    If you bind your POCO entities to a View (through a wrapping ViewModel) it is not only OK but you even must implement IDataErrorInfo on the POCO class if you want to leverage the built-in property validation of the WPF binding engine. Although this interface is mainly used together with UI technologies it is part of System.ComponentModel namespace and therefore not directly tied to any UI namespaces. Basically IDataErrorInfo is only a simple contract which supports reporting of the object's state which also might be useful outside of a UI context.

    The same is true for the INotifyPropertyChanged interface which you also would need to implement on your POCO classes if you bind them directly to a View.

    I often see opinions which would disagree with me for several architectural reasons. But none of those opinions argue that another approach is easier. If you strictly would want to avoid to have POCO model classes in your ViewModel layer, you need to add another mapping layer with additional complexity and programming and maintenance effort. So I would vote: Keep it simple as long as you do not have a convincing reason and clear benefit to make your architecture more complex.

    0 讨论(0)
  • 2021-02-09 03:25

    What you're doing is basically the Repository pattern, for which Entity Framework and POCO are a great fit.

    So, my ViewModels in my MVVM UI app will be communicating with the above BLL class and exchanging BookInfo instances. Is that okay?

    That's exactly what POCO objects are for; there's no difference between the classes that are generated and how you would write them by hand. It's your ObjectContext that encapsulates all the logic around persisting any changes back to the database, and that's not directly exposed to your UI.

    I'm not personally familiar with IDataErrorInfo but if right now your entities will only be used in this single app, I don't see any reason not to put it directly in the generated classes. Adding it to the T4 template would be ideal if that's possible, it would save you having to code it by hand for every class if the error messages follow any logical pattern.

    Also, if you see something terribly wrong with the way I'm trying to build my BLL, please feel free to offer help in that area too.

    This isn't terribly wrong by any means, but if you plan to write unit tests against your BLL (which I would recommend), you will want to change your ObjectContext member to IObjectContext. That way you can substitute any class implementing the IObjectContext interface at runtime (such as your actual ObjectContext), which will allow you to do testing against an in-memory (i.e. mocked) context and not have to hit the database.

    Similarly, think about replacing your List<BookInfo> with an interface of some kind such as IList<BookInfo> or IBindingList<BookInfo> or the lowest common denominator IEnumerable<BookInfo>. That way you're not tied directly to the specific class List<T> and if your needs change over time, which tends to happen, it will reduce the refactoring necessary to replace your List<BookInfo> with something else, assuming whatever you're replacing it with implements the interface you've chosen.

    0 讨论(0)
  • 2021-02-09 03:27

    You don't need to do anything in particular... as Mark said, there is no "right" answer. However, if your application is simple enough that you would simply be duplicating your classes (e.g. BookInfoUI & BookInfoBLL), then I'd recommend just using the business classes. The extra layer wouldn't serve a purpose, and so it shouldn't exist. Eric Evans in DDD even recommends putting all your logic in the UI layer if you app is simple and has very little business logic.

    To make the distinction, the application layer should have classes that model what happens within the application, and the domain layer should have classes that model what happens in the domain. For example, if you have a search page, your UI layer might retrieve a list of BookSearchResult objects from a BookSearchService in the application layer, which would use the domain to pull a list of BookInfo.

    0 讨论(0)
提交回复
热议问题