4
votes

Say i have 3 layers

layer 1: WPF Project (contains: xaml, viewmodels, mvvm framework)

layer 2: business logic layer (contains: plain c# classes)

layer 3: entity framework (contains: repository/data access classes)

when you dont want to expose your DAL(layer 3) to View(layer 1) how do you implement the business logic layer well? im having a hard time putting values back and forth the BLL objects and DAL entities.

can you please help?

7
I'm going to be eagerly watching this thread, but my understanding was that you placed your business logic into your model classes. Your model classes have a dependency on your Repository (DAL) classes, and those in turn use EF to access the database. So since your WPF views should have a dependency on your models, I don't see how you would ever need a dependency in your view to your DAL. That said, I use MVC way more frequently than WPF's MVVM pattern, so maybe I'm missing something.Robert Christ
@RobertChrist MVVM is a bit different from MVC. In MVVM, the Models are simply plain data objects while the ViewModels should be handling application/business logic and data access.Rachel

7 Answers

4
votes

Entity Framework doesn't work really well in a "disconnected" model. Unless something has changed, I've never been able to get it to work great easily.

You could use AutoMapper in Layer 2 to create ViewModels to present to Layer 1, but then you'd still have to send the changes back to Layer 3, which could be a pain.

3
votes

If you're only developing a small app that will not change in the foreseeable, then just do whatever is quickest now. If you want a long-term maintainable app, then let me put forth the following.

The problem with this vertical layer approach is that whenever you need something in the view, you will have to add it to both the Business Layer (even if the business layer doesn't care about it), and the Data Layer. This requires your business layer to look like 1) UI views of the data 2) business views of the data and 3) the database representation of the data. That and/or you need a lot of mapping in-between layers. All of which dilutes business layer's actual purpose of representing business logic. What tends to happen then is that all the business logic gets migrated into transaction methods (that could just as well be static methods) to just change states on data objects. There's nothing at all wrong with that if your problem domain is nothing but CRUD with no complex logic. With complex logic, such business methods can get pretty tricky or even have undefined outcomes (because complex interdependencies on "fields" can be contradictory and hard to resolve).

Assuming you have complex logic, user views of data and business representations of data are often very different, and so UI views end up with specialized models of the data. If I were you, I just embrace this and use a simple version of the CQRS principle. That is, have the data for your UI views come from a different place than where your business operations are executed. In your case, I might have an EF Model in your DAL that only services your UI views, and gives them exactly what they need (whether by database views, stored procedures, or pre-compiled report tables). Then create a separate EF model that services only the needs for your Business entities. Then when you are ready to perform an actual business action, the UI's viewmodel action method can load the business object from the business EF model (or better yet, call an object factory from the business layer which does this) and run an appropriate action on the business object. Note that I'm also making the assumption here that your database is highly relational (mostly 2nd and 3rd normal form) and you are set on using EF.

I would not try to make your View Models into business logic. This makes your business logic not easily reusable on other platforms or applications (like web). MVVM should only service the UI. In my mind, the V (view) represents what the user sees and operates. The M (model) represents what the user chose on that view. And the VM (view model) translates between the two. Your program should then take the user's validated choices (UI model) and extract the needed data out of it to perform an appropriate business operation.

2
votes

Instead of exposing all of your DAL to View Layer, just exchange your domain objects (EF objects) between all layers. The structure may be similar to the following:

  1. Presentation Layer-------- ^
  2. BLL --------------------------- | Data objects
  3. DAL (Repositories etc.)--- |

So, all of your layers will be disconnected; but they will share the same domain objects. In real world, you can implement a similar structure by creating a seperate dll for Entity Framework entities which is shared by all layers. Note that ObjectContext shall be only visible to DAL (by default, entities and object context are generated in the same dll, you need to seperate this into two dlls).

1
votes

In addition to the answer by Daryal, you can define your business-objects in your BL to be POCO's, and use EF in your DAL layer to read them from or persist them to the database.

If you define an repository-like interface in your BL (or unit-of-work, whatever naming you give it), and implement the interface in your DAL, then all you need is a little DI to get an instance of the repository-class without having to reference the DAL all the time. It works like a charm for me.

See here and here for more information.

1
votes

Your ViewModels are your application in MVVM, so they should be handling things like data access through your Repository classes, or business logic (either directly, or indirectly using your validation classes).

If you don't want to directly reference the classes, use an Interface but be aware that you'll need to have some way of passing your inherited class to your ViewModel. I once did a project where we had a library of shared interfaces, such IRepository interfaces, and everything was imported/exported using MEF so the layers didn't reference each other directly.

The final (simplified) layout was:

  • Models -> Contained plain data objects that could do simple validation on their own data (length, min/max values, etc) but that didn't do any advanced validation or business logic. Did not reference any other library.

  • Common -> Contained interfaces, utilities, and other commonly shared classes. Referenced the Model library only.

  • DAL -> Contained Data Access and Repositories based on repository interfaces found in Common library. Referenced Common library for interface definitions and utilities, and Model library because it contained the data models used or returned in data access calls

  • ViewModels -> Contained application and business logic. Referenced Common for its utilities and interfaces, and Models for the data models

  • Client -> Contained Views. Referenced Models and ViewModels so it could write DataTemplates for both object types

0
votes

Entity framework is suppouse to be used as "Logic Layer" by itself.

Your idea may have some sense, to use combine technologies.

Howevere, I think some of those Micros. libraries, where designed to be used separately, unless, otherwise explicitly combined & mentioned in their websites.

Good Luck.

0
votes

I second daryal and I have implemented this in some projects. It is absolutely OK to use POCO as business objects.

Another approach instead of creating 2 projects (one for DB Context and one for Entities) is to use one DAL/DATA project only and reference it in BLL. Then inherit the POCO class in BLL and use that class in UI layer. Below is the basic sample code:

// assume this is EF generated POCO
namespace Owner.Project.Data{
    public partial class Product
    {
        public int ProductId { get; set; }
        public string ProductName { get; set; }
    }
}

// this is manually created class in BLL
using Owner.Project.Data;
namespace Owner.Product.Business{
    public class StoreProduct : Product {
        public bool Add (string productName){
            // TODO - add product using EF as you normally do
        }
    }
}

Now you can reference the BLL in your UI project and use StoreProduct class there. To achieve loosely coupled pattern, Of course you could also inherit the StoreProduct class from an IStoreProduct interface and make use of it in UI or web service but that is another topic.