Application independent of database schema - asp.net

I have an asp.net application that uses the entity framework to interact with the database.
In the new version that I am working on now, I need to separate the application from the database so that it can be used with a variety of databases that have similar data but different schemas. (Able to be used for new clients)
So far this is my approach, but it feels wrong
I have objects from a data entity model generated by the clients database
I custom wrote objects that my system will use
I wrote an interface that outlines all of the data operations that return my custom objects
I wrote an implementation of the interface that takes my client's objects from the entity framework connected to their database, and loads the fields I want into my custom objects.
This feels wrong as now I have 2 sets of similar objects.
Example, here I get salesOrders from the clients database, and dump the data into my custom Job object:
public List<Job> getJobs()
{
List<Job> jobs = new List<Job>();
using (var context = new TBDIEntities.TBDIEntities())
{
//get all future events that are not cancelled
List<SalesOrder> salesOrders = context.SalesOrders
.Where(c => c.EVENTCONFIRMATION != "CANCELLED" && c.FUNCTIONDATE >= DateTime.Now)
.ToList<SalesOrder>();
jobs.AddRange(from order in salesOrders
let dateTime = order.FUNCTIONSTARTTIME
where dateTime != null
select new Job
{
Description = order.FUNCTIONTYPE,
StartTime = (DateTime)dateTime,
Id = order.SALESORDERREF_TXNID.ToString(),
ShiftGroups = new List<ShiftGroup>(),
Status = order.EVENTCONFIRMATION,
ShiftCount = (int)context.BSS_ShiftListView
.Count(c => c.SALESORDERREF_TXNID == order.SALESORDERREF_TXNID),
ConfirmedShifts = (int)context.BSS_ShiftListView
.Count(c => c.SALESORDERREF_TXNID == order.SALESORDERREF_TXNID && c.Confirmed != null),
Client = new Client { Name = order.CustomerRef_FullName }
});
}
return jobs;
}
So I am creating a new context, getting a collection of salesOrders (the table name in the clients database), then taking the the data from the salesOrders and creating new Job objects (the ones I wrote that my application will interact with) and returning the Job objects.
This feels wrong as now I have 2 lists of similar objects (SalesOrders and Jobs), and I have to write CRUD operations for each object rather than just using the entity framework.
Example, I have a page where you can add new shifts. But the Shifts table will be different from client to client, and changes I make need to update the clients table. So how do I write code that can use shifts, but can have the entity framework swapped out with schemas from new clients? I need things like shifts to be in a collection that I can use to databind an asp:ListView.
What is the smartest way of doing this? How do I use the entity framework but be independent of customer schema so my project can be reused for many databases?

Your two similar objects are really performing two different roles for your architectural layers and are not redundant. What you're working with are Domain Models (SalesOrders), Data Transfer Objects, and View Models (Jobs). So you really might end up with 3 sets of objects.
A tool like AutoMapper takes out much of the pain of the tedious object-to-object mapping.

Related

Symfony. Using transactions with 2+ repositories

In a certain controller I need to do several inserts/updates in the database. I'm using 4 repositories of 4 entities for that, but I need this to be done in a unit of work.
I know that I can do these inserts/updates directly on the controller and use $em->getConnection()->beginTransaction(), $em->getConnection()->rollBack() and $em->getConnection()->commit() to ensure that all or none are done. But this goes against symfony best practices, so I'd like to use repositories.
I've seen this tutorial for Doctrine 1, but it seems like a very complex solution to something that is supposed to be simpler.
Any idea?
Thank you in advance.
edit, I'm using Symfony 3.3.5.
edit2, I add an example of what I want to do. The whole process is to add a message written by a worker to the rest of his department mates, all within a company. The message may or may not have attachments (let's say it does). These files should appear as department and company files, so that even if the department is deleted, the files continue to appear as belonging to the company.
I haven't included error handling in the code to make it simpler.
// New Files
$file1 = new File(); // AppBundle\Entity\File
$file1->setName("name1");
$file2 = new File();
$file2->setName("name2");
$em->getRepository('AppBundle:File')->insert($file1);
$em->getRepository('AppBundle:File')->insert($file2);
// New Post
$post = new Post(); // AppBundle\Entity\Post
$post->setContent($some_text)
->setAuthor($some_user) // AppBundle\Entity\User
->addFile($file1)
->addFile($file2);
$em->getRepository('AppBundle:Post')->insert($post);
// Getting company and department
$company = $em->getRepository('AppBundle:Company')->findOneByCode($some_company_code);
$department = $em->getRepository('AppBundle:Department')->findOneByCode($some_dept_code);
$company->addFile($file1)->addFile($file2);
$department->addFile($file1)->addFile($file2);
$em->getRepository('AppBundle:Company')->update($company);
$em->getRepository('AppBundle:Department')->update($department);
// Notifications
$notif = new Notification(); // AppBundle\Entity\Notification
$notif->setText("Text")
->setPost($post)
->addAddressee($some_dept_member)
->addAddressee($other_dept_member);
$notif = $em->getRepository('AppBundle:Notification')->insert($notif);
In repositories you should only fetch entities or execute queries with DQL that retrieve some data.
Every time you need to create a new row in your db, you have to inform the entity manager that you want to persist the entity, calling $em->persist($myNewEntity). This inform the entity manager that that entity should be persisted to dB.
Once you have created (and persisted) all your entities and/or modified your fetched entities, you can call $em->persist() just once: the entity manager will do all the needed insert/update/delete in a single transaction to your dB.
If you also need to retrieve/fetch data in the same transaction you should consider including all your code in a callback function and pass it to the entity manager, like this
$myCallback=function($em) {
//Do all here: access repositories, create new entities, edit entities
//...
//no need to call $em->flush(), it will be called by Doctrine after the execution of the callback
};
$em->transactional($myCallback) ;

Is it a good practice to pass IQueryable as parameter in a Service layer method?

I have an ASP.NET application with 3 layers UI, Service Layer and Repository.
I have to implement a search functionality on the products in the database.
ProductRepository is my repository class and the signature of the method that gets all the products from the database is:
IQueryable<Product> GetAllProducts();
Therefore from my Service Layer I use:
IProductRepository _ProductRepository = new ProductRepository();
IQueryable<Product> products = _ProductRepository.GetAllProducts();
If I would like to filter IQueryable<Product> products, for instance by taking those product with price > 100 or just those with color = "yellow".
So I was wondering, instead of creating methods in ProductRepository such as:
IQueryable<Product> GetAllProductsByColor(int colorId)
I was wondering if it is a good practice to create in my Service Layer a set of methods that accept IQueryable<Product> as parameter and perform the filtering directly there:
IQueryable<Product> FilterProducts(IQueryable<Product> products, Dictionary<string, object> filters)
Where Dictionary<string, string> represent a set with (propertyName, value).
The advantage of this solution is that if I have to apply multiple filters I just pass the IQueryable<Product> already filtered, instead of taking everytime the intersection between the filtered product sets.
Is it a good practice (as long as I keep the context open) or it is not "allowed"by the multi-layered architecure pattern?
I'd say it depends on what provides the implementation of your IQueryable. In most cases, you run the risk of allowing users of your IQueryable to either 1) filter on fields that are not indexed (thus hosing the database layer, if you have any, when you have large tables), or 2) execute arbitrary IQueryable operations that put a huge load on the database (such as GroupBy's, Join's, etc.).
Assuming you are OK with 1, in order to prevent 2) I usually allow users to load objects through a IEnumerable<Product> LoadProducts(Predicate<Product> filter) method which I then transform into a Where on the IQueryable; this hides the other IQueryable methods and yet allows full flexibility for filtering purposes only.

MVC + POCO + Entity Framework, Passing Object between layers

I am trying my hands on MVC 2, ADO.NET EF and POCO. I have generated my entity classes in a separate library using POCO generator.These POCO entities are used as ViewPages (Not sure if that's the right way to design or do I need separate ViewModels classes ?)
Now, if I take case of a simple scenario where I need to add an Employee object( which is related to a Department Master), what then should be the recommended way to transfer these objects between layers.
Layered structure of the application is somewhat like this :
I have thought of various alternatives:
I have a method in the Employee Controller which is named AddEmployee() which accepts the FormCollection as parameter. Within the form collection I get posted data such as Employee Name, Age , Salary etc and the ID of the Selected Department .
1.) One way is that I can create another DTO say EmployeeDepartment DTO which will be used to map values from FormCollection as is. I can then break them at manager layer and use them to create entity objects i.e Employee Object and refer department by query similar to this:
e.Department = Department.where(i => i.deptId == empDepDto.dept_id).first()
I am not a big fan of this and feel that every time there is a relation involved I have to add a DTO and then map it to my entity class.
2.) Second is probably the worst, i.e passing each object as parameter and then couple them in manager layer.
3.) Use POCO as is, Create a Employee Object and Deparment Object at controller layer and pass the POCO object
public void AddEmployee(FormCollection formCollection)
{
Department d = new Deparmtent; d.id = ""; //based on the dropdown value
d.name="" //based on the dropdown selected text;
Employee e = new Employee; e.Name. e. sal....
e.Department = d;
EmployeeManager.AddEmployee(e);
}
But at manager layer I think , I still need to recreate the reference to the Department using LINQ which again is repetitive and doesn't seems to be a clean solution.
Are there better ways of handling this ? Looking for recommendations and best practices.
Firstly, is there any reason you're not using MVC version 3? There's no major breaking changes, so may as well upgrade?
Secondly is there a reason for using FormCollection rather than the strongly typed model-binding? Just change your views to use the strongly typed HTML helpers ( like <%: Html.TextBoxFor(m => m.Property) %>), or make sure the name attributes match the property names, and have your controller receive the type, and model binding will do the rest. There's plenty of tutorials showing this, and articles explaining it. Model binding will work with a name/value collection, like that posted as a form, or against JSON data, or you can find/write custom model binders that work against whatever wacky serialisation protocol you want.
One thing to watch though when passing the actual entity types that Entity Framework will store around, is that you have to be careful when updating existing objects, or with foreign key references to existing objects - all your objects must be attached to the right Entity Framework context. To achieve that you will often see the objects received by the controller having their properties copied to a freshly retrieved entity from a context, either manually or by an object mapper of some kind.
Make a seperate project called "BusinessObjects" or "Model" which contains your POCOs. Then use strongly typed model-binding for MVC and you'll be set.
The method signature will look something like this:
// In your Controller
public void AddEmployee(Employee newObject)
{
YourDataContext dc = new YourDataContext();
dc.Employees.Add(newObject);
dc.SaveChanges();
}

ASP.NET EntityFramework 4 data context issues

I'm working on a site and there are two projects in the solution a business logic project and the website project. I understand that I want to keep the entity context out of the web project and only use the business objects the framework creates but I can't figure out how to save a modified object this way.
Let's say my entity model created this class:
public class Person //Person entity
{
Int32 Id {get;set;}
String Name {get;set;}
Address Address {get;set;} //Address entity
}
And I created this class to get a specific person:
public static class PersonController
{
public static Person GetById(int id)
{
using (Entities context = new Entities())
{
return context.Persons.FirstOrDefault(x => x.Id == id);
}
}
}
This allows me to get a person without a context by calling PersonController.GetById(1); and I can change the persons properties after I get them but I can't figure out how to save the modified information back to the database. Ideally I would like to partial class Person and add a .Save() method which would handle creating a context adding the person to it and saving the changes. But when I tried this a while ago there were all kinds of issues with it still being attached to the old context and even if I detatch it and attatch it to a new context it gets attached as EntityState.Unchanged, if I remember right, so when I call context.SaveChages() after attaching it nothing actually gets updated.
I guess I have two questions:
1) Am I going about this in a good way/is there a better way? If I'm doing this in a really terrible way I would appreciate some psudo-code to point me in the right direction; a link to a post explaining how to go about this type of thing would work just as well.
2) Can someone provide some psudo-code for a save method? The save method would also need to handle if an address was attached or removed.
There are many ways to handle Entity Framework as a persistence layer.
For one, it looks like you're not using pure POCOs. That is, you let EF generate the classes for your (in the EDMX.designer.cs file).
Nothing wrong with that, but it does inhibit a clean separation of concerns (especially when it comes to unit testing).
Have you considering implementing the Repository pattern to encapsulate your EF logic? This would be a good way to isolate the logic from your UI.
In terms of Save - this is where it gets difficult. You're right, most people use partial classes. Generally, you would have a base class which exposes a virtual "Save" method, which the partial classes can then override.
I personally don't like this pattern - i believe POCOs should not care about persistence, or the underlying infrastructure. Therefore I like to use pure POCOs (no code gen), Repository pattern and Unit of Work.
The Unit of Work handles the context opening/saving/closing for you.
This is how (my) Unit of Work does the magic. Consider this some code in your "Web" project:
var uOw = new UnitOfWork(); // this is class i created, implementing the UOW pattern
var person = repository.Find(10); // find's a "Person" entity (pure POCO), with id 10.
person.Name = "Scott";
uOw.Commit();
Or adding a new Person:
var uOw = new UnitOfWork();
var newPerson = new Person { Name = "Bob" };
repository.Add(newPerson);
uOw.Commit();
How nice is that? :)
Line 1 creates a new sql context for you.
Line 2 uses that same context to retrieve a single "Person" object, which is a hand-coded POCO (not generated by EF).
Line 3 changes the name of the Person (pure POCO setter).
Line 4 Saves the changes to the data context, and closes the context.
Now, there is a LOT more to these patterns than that, so I suggest you read up on these patterns to see if it suits you.
My repository is also implemented with Generics, so I can re-use this interface for all business entity persistence.
Also take a look at some of the other questions I have asked on Stack Overflow - and you can see how I've implemented these patterns.
Not sure if this is the "answer" you're looking for, but thought I'd give you some alternative options.

DataTable Wrapper or How to decouple UI from Business logic

I am using web forms, C#, Asp.net.
As we all know, in this model UI and business logic are often mixed in. How do I separate these effectively?
The example I would like to use is:
I have a GridView and a DataTable (GridView binds to the DataTable and DataTable is fed from the stored procedure).
I would like the GridView (UI) and DataTable (business logic) to be decoupled.
Is it worth it to write an wrapper for DataTable? Are there practical patterns that have been proved and tested that you could recommend to be followed?
If someone with experience could shed some light, that would be awesome.
And, as a final note I would like to say that ASP MVC is not an option right now, so don't recommend it.
My database access layer returns a DataTable.
Note that I HAVE to use this database layer as this is a company policy.
I went through this recently while decoupling much the same thing from our UI layer.
You can see my progress here and here.
In my opinion, A DataTable does not represent business logic. Specifically, it's data pulled directly from the database. Business logic turns that data into a truly useful business object.
The first step, then, is to decouple the DataTable from the Business object.
You can do that by creating objects and List<object> that make up DataTables and Collections of DataTables, and then you can make a ListView that displays those Objects. I cover the latter steps in the links I posted above. And the former steps are as easy as the following:
Create a class that will represent your object.
iterate through your DataTable (or DataSet, or however you retrieve the data) and shove those fields into properties of that object (or that List<T>);
return that List to the Gridview or ListView to display.
This way your ListView or Gridview won't be tightly coupled to the method that you are retrieving your data. What happens if you decide to get your data from a JSON query or a XML file later on? Then you'd have to build this into there.
Step 1 - Getting Data From Database
There are multiple methods to get data from a database, there's no way I can go through all of them here. I assume that you already know how to retrieve data from a database, and if you don't, there are quite a few links to follow. Let's pretend you've connected to the database, and are using an SQLDataReader to retrieve data. We'll pick up there.
Class Diagram
Foo
----
id
Name
Description
And here's the method:
private void FillDefault(SqlDataReader reader, Foos foo)
{
try
{
foo.id = Convert.ToInt32(reader[Foo.Properties.ID]);
foo.Name = reader[Foo.Properties.NAME].ToString();
if (!string.IsNullOrEmpty(
reader[Foo.Properties.DESCRIPTION].ToString()))
foo.Description =
reader[Foo.Properties.DESCRIPTION].ToString();
else foo.Description = string.Empty;
}
catch (Exception ex)
{
throw new Exception(
string.Format("Invalid Query.
Column '{0}' does not exist in SqlDataReader.",
ex.Message));
}
}
Once that happens, you can return a list by going through that process in a while loop that targets the SQLDataReader.Read() function.
Once you do that, let's pretend that your Foo being returned is a List. If you do that, and follow the first link I gave above, you can replace Dictionary<TKey, TValue> with List<T> and achieve the same result (with minor differences). The Properties class just contains the column names in the database, so you have one place to change them (in case you were wondering).
DataTable - Update Based on Comment
You can always insert an intermediate object. In this instance, I'd insert a Business Layer between the DataTable and the UI, and I've discussed what I'd do above. But a DataTable is not a business object; it is a visual representation of a database. You can't transport that to the UI layer and call it de-coupled. They say you have to use a DataTable, do they say that you have to transport that DataTable to the UI? I can't imagine they would. If you do, then you'll never be de-coupled. You'll always need an intermediate object in between the DataTable and the UI layer.
I'd start by decoupling the data table right into the trash can. Build a domain layer, and then some type of data access layer which deals with the DB (ORM recommended).
Then build a servicing layer which provides the data to the UI. All business logic should be within the service or the entities themself.
Consider implementing MVP (model view presenter) pattern. It gives you separation of biz logic through presenter interface, which also allow better unit testing capabilities. Your codebehind of aspx page is then just connector of events and getter/setter of properties. You can find it in MS pattern&practices enterprise application blocks (CAB - composite application block - if i'm not mistaking).
You can read more about it here: http://msdn.microsoft.com/en-us/magazine/cc188690.aspx
But also going from DataTable/DataSets to objects (POCO) is preferred.

Resources