I would like to improve my .NET project by adding another layer when accessing the database. This is my code:
namespace Company.Models
{
public static class AgencyBean
{
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public static String createGUID(string name)
{
DataAccess dataAccess = new DataAccess();
bool exists = dataAccess.checkIfExists(Id);
if(exist)
{
dataAccess.delete(Id);
}
retur "ok";
}
}
}
I placed DataAccess class in a separate folder called "Helpers" and it contains most of my queries:
public class DataAccess
{
public bool checkIfExists(String Id)
{
try
{
SqlConnection cnn = new SqlConnection(dataConnection);
cnn.Open();
SqlCommand check_Id = new SqlCommand("SELECT COUNT(*) FROM TABLE_GUID WHERE ([USER_ID] = #Id)", cnn);
check_Id.Parameters.AddWithValue("#Id", Id);
int UserExist = (int)check_Id.ExecuteScalar();
if (UserExist > 0)
{
return true;
}
else
{
return false;
}
}
catch (SqlException ex)
{
Debug.WriteLine("SQL Exception " + ex);
DisplaySqlErrors(ex);
throw ex;
}
}
}
public class AgentBeanController : Controller
{
// GET: AgentBean
public ActionResult Index(string name)
{
return View();
}
[AllowAnonymous]
[WebMethod]
public string AgentURL() //here we create Agent URL and return it to the view
{
string var = Models.AgentBean.createGUID("TODO");
return var;
}
}
I'm accessing the database pretty much in very direct way. How would it be with a better technique, so this access can be more secure, like accessing thru a service layer?
I'm connecting to a existing sql database in some server and working with MVC architecture in my project.
So here is what I have done in the past.
First, that is your "models" namespace... models should never have database connectivity. Instead you have a seperate class, such as a controller, that hydrates some model.
Second, I've had a "service" class, which hooks up to a "repository" class. The repository class implements an interface to identify the exact "type" of database you're using.. but if that's not a part of your requirements you probably don't need to go that far.
Third, look up dependency injection (aka, DI). There are several frameworks out there. Personally I've used Autofac, but others exist as well to get the job done easier.
Fourth, on your your "controllers", "services" and "respository" classes, implement dependency injection, as well as any interfaces as needed to form a contract.
Fifth, I would use an actual controller namespace and not be working out of your models namespace to be pushing http calls band and forth.... Instead, create an action in your controller class, and instantiate an instance of your "agencyBean", hydrate it with data, and return that model out to your view.
Basically, in a scenario like this you're trying to keep each component doing what it is designated to do... breaking down responsibilities into smaller pieces and focusing on that. Your controller should just "fetch" your model and maybe do some transformations on it as needed or any other business-type logic.
Your service should handle the communication between your controller and your database layer.
Your data access layer (ie, in this case, some "repository" class...) would do all of those new data connections and/or setting up calls to stored procedures or queries.
Doing things this way has a lot of benefit. Some of the big ones are maintainability, readability, code re-use. Sure it makes your project a bit more complicated in terms of files sitting wherever... but that can be a good thing. It's so much better than slamming everything into one single class and have it do everything :)
But, just FYI, this is from an implementation I've done in the past... I'm sure there are better ways but this setup worked quite well for my team and I.
Here is a small example using some of your code you posted. I DID NOT check this for typos and it wouldn't compile, but should help give a general idea of what I'm talking about....
namespace Company.Models
{
public class AgencyBean
{
public AgencyName{get;set;}
public AgencyId{get;set;}
// other properties...
}
}
namespace Company.Controllers
{
public class MyController : Controller
{
private readonly IMyService myService;
public MyController(IMyService myService) // <-- this is your dependency injection here...
{
this.myService = myService;
}
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public static String createGUID(string name)
{
var model = new AgencyBean();
model.AgencyId = 1;
model = myService.getAgency(agencyBean);
return model;
}
}
}
namespace Company.Services
{
public class MyService
{
private readonly IMyRepository myRepository;
public MyService(IMyRepository myRepository) // <-- this is your dependency injection here...
{
this.myRepository = myRepository;
}
public AgencyBean getAgency(AgencyBean model){
var dataTable = myRepository.getAgencyData(model.AgencyId);
// fill other properties of your model you have...
// ...
// ...
return model;
}
}
}
namespace Company.Repositories
{
public class MyRepository : IDatabaseCommon // <-- some interface you would use to ensure that all repo type objects get connection strings or run other necessary database-like setup methods...
{
private readonly String connectionString{get;set;}
public MyRepository()
{
this.connectionString = //get your connection string from web.config or somewhere else...;
}
public DataTable getAgencyData(int id){
var dataTable = new DataTable();
// perform data access and fill up a data table
return dataTable;
}
}
}
Related
I am working on a project(asp.net mvc-5 with jQuery) in which whole validation is happening in front-end and we are executing api's using $.ajax call, now as there are no validations on api level or not even in stored procedures of sql server, a user can easily access the the api's with wrong values, so We decided to add a logic layer in our application
so before that our structure looks like the below
jQuery -> Api layer -> Db layer
now I want to add a layer between Api layer and Db layer which will be called as Logic layer
the new structure will look like below
jQuery -> Api layer -> Logic layer -> Db layer
Note:
all the layers are different projects in same solution
Logic layer and Db layer is a class library file
Db layer is divided into 2 sub catogories (interface and class)
So we have 4 class library 1 api and 1 front end
interfaces are inherited in the class files
the class library is like below
db.Interface(class library project)
db.Class(class library project)
Logic.Interface(class library project)
Logic.Class(class library project)
We have already added dependencies for db layer the code for which looks like below,
Set of code In global.asax.cs
//Helps to find all the classes of Dblayer
string dbName = ConfigurationManager.AppSettings["DB"];
string dbDAL = Path.Combine(Server.MapPath("./DAL"), "DocPro.DMS.BusinessLayer." + dbName + ".dll");
AssemblyName an = AssemblyName.GetAssemblyName(dbDAL);
Assembly assembly = Assembly.Load(an);
Type[] assemblyTypes = assembly.GetTypes();
DALFinder.Initialize(assemblyTypes);
class file in api project called DalFinder
public static class DALFinder
{
private static List<Type> TypeList { get; set; } = new List<Type>();
public static void Initialize(Type[] typelist)
{
TypeList.Clear();
TypeList = typelist.ToList<Type>();
}
public static object GetInstance(Type plugin)
{
foreach (Type type in TypeList)
{
if (type.IsInterface || type.IsAbstract)
{
continue;
}
else
{
if (type.GetInterface(plugin.FullName) != null)
{
return Activator.CreateInstance(type, new object[] { Program.GetConnectionString() });
}
}
}
return null;
}
}
and while executing a particular function I needed to do the below in my Api layer
BusinessLayer.IAdmin.IFolderRole a = (BusinessLayer.IAdmin.IFolderRole)DALFinder.GetInstance(typeof(BusinessLayer.IAdmin.IFolderRole));
response = a.SaveFolderRole(item);
now for my current scenario I want to call db layer from my logic layer but since it is a class library file I failed to understand what should I do, for now I did something like below
public class DocTemplateController : ApiController
{
private LogicLayer.IAdmin.IDocTemplate _LogicLayer;
private BusinessLayer.IAdmin.IDocTemplate _Businesslayer;
public DocTemplateController()
{
_LogicLayer = (LogicLayer.IAdmin.IDocTemplate)BusinessLayerFinder.GetInstance(typeof(LogicLayer.IAdmin.IDocTemplate));
_Businesslayer = (BusinessLayer.IAdmin.IDocTemplate)DALFinder.GetInstance(typeof(BusinessLayer.IAdmin.IDocTemplate));
}
[HttpPost]
[Route("api/Admin/DocTemplate/GetDocTemplates")]
[Authorize]
[Filters.AuthorizeLoginApi()]
public async Task<GetTemplatesList> GetDocTemplates(DocTemplate request)
{
var response = new GetTemplatesList() { LogicLayerValidation = false };
try
{
response = _LogicLayer.GetDocTemplates(request);
if (response.LogicLayerValidation != false)
response.GetTemplates = await _Businesslayer.GetDocTemplates(request.TemplateName, request.AccountId);
}
catch (Exception ex)
{
Utils.Logger.Instance.LogException(ex);
response.LogicLayerValidation = false;
response.LogicLayerMessage = ex.Message;
}
return response;
}
}
and as I understand (I might be wrong) that this is a bad way of coding, I want to follow the structure of
jQuery -> Api layer -> Logic layer -> Db layer
how can I do this?
EDIT:
After I put bounty on the question I received lots of answers, but I
think so I needs to edit this question and provide more details, (all
the answers are good and can be very helpful for many but
unfortunately I am failed to get what I wanted)
this is how my controller looks like,
[RateLimitApi]
public class UserController : ApiController
{
private readonly LogicLayer.IAdmin.IUsers _LogicLayer;//Logic layer
private readonly LogicLayer.IGlobalValidation _CommonLogicLayer; //common logic layer
private readonly BusinessLayer.IAdmin.IUsers _Businesslayer;// business layer
private readonly BusinessLayer.IAccess.IUser _IAccessBusinesslayer;//business layer which is being used in another api
private BusinessEntities.Response.LogicLayerValidationResult _Llv; //entity for logiclayer
private SPResponse _Sp; //response entity for add/edit
private readonly ErrorLogger _Er; error log class
private readonly BusinessEntities.Response.Admin.GetUsersList _UserList; //user list
private readonly BusinessEntities.Response.Admin.GetUsersSingle _UserSingle; //single user
public UserController()
{
_LogicLayer = (LogicLayer.IAdmin.IUsers)BusinessLayerFinder.GetInstance(typeof(LogicLayer.IAdmin.IUsers));
_Businesslayer = (BusinessLayer.IAdmin.IUsers)DALFinder.GetInstance(typeof(BusinessLayer.IAdmin.IUsers));
_IAccessBusinesslayer = (BusinessLayer.IAccess.IUser)DALFinder.GetInstance(typeof(BusinessLayer.IAccess.IUser));
_CommonLogicLayer = (LogicLayer.IGlobalValidation)BusinessLayerFinder.GetInstance(typeof(LogicLayer.IGlobalValidation));
_Llv = new BusinessEntities.Response.LogicLayerValidationResult() { LogicLayerValidation = false };
_Sp = new SPResponse();
_Er = new ErrorLogger();
_UserList = new BusinessEntities.Response.Admin.GetUsersList();
_UserSingle = new BusinessEntities.Response.Admin.GetUsersSingle();
}
// GET: Admin/Users
[HttpPost]
[Authorize]
[ActionName("GetList")]
[Filters.AuthorizeLoginApi()]
public async Task<BusinessEntities.Response.Admin.GetUsersList> GetList(DocPro.DMS.BusinessEntities.Request.Admin.UsersRequest request)
{
try
{
// had to call logic layer and then call the business layer like below
_Llv = _LogicLayer.GetList(request);
if (_Llv.LogicLayerValidation)
{
_UserList.GetUsers = await _Businesslayer.GetList(request.LoginText, request.Name, request.Email, request.UserTypeId, request.IsActive, Convert.ToInt32(request.LoggedInUserId));
}
}
catch (Exception ex)
{
_Llv = _Er.LogExceptionWithLogicLayerValidations(ex, _Llv);
}
_UserList.LogicLayerValidation = _Llv;
return _UserList;
}
}
how can I do this?
is quite a general question (which is frown upon in this community).
I don't see any issue with the structure:
jQuery -> Api layer -> Logic layer -> Db layer
It is very common structure: frontend -> api-> business (logic) layer-> db
If it is a new project, I might recommend to do it with .net core and use the microsoft dependency injections or maybe use Autofac, since the topic is complex. If you really want to do it, then you can also browse their (ms or autofuc) code on github to familiarize yourself on the topic.
you should add a reference to your databaselayer project in your logic layer project. Then you can inject the db layer class in your logic layer class using dependency injection.
Then you can just call the db layer from the logic layer after you are done validating.
Why reinvent the wheel?
what you are asking for is already implemented in AspNet Boilerplate
More on this here
I have been following this tutorial in order to get access to my appsettings.json from my MVC project inside my class library.
geek-tutorial
I have a class as such in my class library
using dapper;
public class SqlDataAccess : IConfigManager
{
private readonly IConfiguration _configuration;
public SqlDataAccess(IConfiguration configuration)
{
this._configuration = configuration;
}
public List<T> LoadData<T>(string sql)
{
using (IDbConnection cnn = new SqlConnection(GetConnectionString()))
{
return cnn.Query<T>(sql).ToList();
}
}
public int SaveData<T>(string sql, T data)
{
using (IDbConnection cnn = new SqlConnection(GetConnectionString()))
{
return cnn.Execute(sql, data);
}
}
public string GetConnectionString(string connectionName = "URLShortnerDB")
{
return this._configuration.GetConnectionString(connectionName);
}
}
Interface:
public interface IConfigManager
{
string GetConnectionString(string connectionName);
}
I have added services.AddSingleton<IConfigManager, SqlDataAccess>(); in my mvc startup.cs
However now I would like to use my SqlDataAccess class and call methods from another class e.g:
public static class ShortUrlProcessor
{
public static ShortURLModel GetOriginalURL(string shortUrl)
{
string sql = $#"SELECT * FROM dbo.shorturl WHERE shortUrl = '{ shortUrl }'";
var originalURLEnum = SqlDataAccess.LoadData<ShortURLModel>(sql); //<--- problem
return originalURLEnum.First();
}
}
However SqlDataAccess is not instantiated, and in order to do var _sqldataaccess = SqlDataAccess() I need to pass in a parameter as defined in the constructor of the class. I do not know what to pass in? I do not have any IconfigurationManager in this ShortUrlProcessor class. I understand the reason of doing this is dependancy injection, however I am still not grasping how this all works?
You're very close, but you need to fix a few things. SqlDataAccess implements IConfigManager. Why? What's that providing? Instead, you should have it implement an interface that allows it to expose the functionality other classes depend on.
public interface ISqlDataAccess
{
List<T> LoadData<T>(string sql);
int SaveData<T>(string sql, T data);
}
Change your SqlDataAccess class to implement this interface...
public class SqlDataAccess : ISqlDataAccess
And of course, wire this up with your DI container.
services.AddTransient<ISqlDataAccess, SqlDataAccess>();
Now, any class that needs to run SQL can take a dependency on the ISqlDataAccess interface, utilizing constructor injection to get an instance of ISqlDataAccess. Since we've told the DI container to provide a SqlDataAccess instance when the ISqlDataAccess dependency is present, it will all wire up nicely in your app.
Then we have the issue with ShortUrlProcessor. You declared that class as static. That's bad, because it makes it difficult for it to use constructor injection to get its dependencies, and any other class that needs to invoke its methods has to do so directly, rather than via an abstraction. That violates the Dependency Inversion Principle of SOLID. And since we should always strive to write SOLID code because of the maintainability and testability, we need to fix that.
public class ShortUrlProcessor : IShortUrlProcessor
{
readonly ISqlDataAccess _dataAccess;
public ShortUrlProcessor(ISqlDataAccess dataAccess)
{
_dataAccess = dataAccess;
}
public ShortURLModel GetOriginalURL(string shortUrl)
{
string sql = $#"SELECT * FROM dbo.shorturl WHERE shortUrl = '{ shortUrl }'";
var originalURLEnum = _dataAccess.LoadData<ShortURLModel>(sql); //<--- problem
return originalURLEnum.First();
}
}
And we'll need an interface so other classes don't have to depend directly on ShortUrlProcessor...
public interface IShortUrlProcessor
{
ShortURLModel GetOriginalURL(string shortUrl);
}
And of course, we need to register it with our DI container.
services.AddTransient<IShortUrlProcessor, ShortUrlProcessor>();
Then any class that needs to access the functionality of ShortUrlProcessor can do so via the abstraction IShortUrlProcessor. You mentioned you have a controller calling this, so let's wire that up too.
public class MyController()
{
readonly IShortUrlProcessor _shortUrlProcessor;
public MyController(IShortUrlProcessor shortUrlProcessor)
{
_shortUrlProcessor = shortUrlProcessor;
}
public ActionResult SomeActionMethod()
{
var model = _shortUrlProcessor.GetOriginalURL("asdf");
return View(model);
}
}
We don't have to create an interface for the controller, because the controller will be called by the framework. And we don't have to wire up the controller with the DI container, because the framework handles that for us.
By doing all this, we can easily test individual methods in isolation. There's still some improvements to be made (the SQL Injection attack I mentioned in the comments needs to be fixed), but it's a good step in the right direction.
I have simple classes to saves and get data (not like repository pattern). But while saving data to multiple tables I want to maintain a transaction. So I just went through Unit of work pattern, but that will require me to do a lot of changes. So I'm thinking if my approach will do the same as UOF.
Here's my code:
CalalogueRepository:
public interface ICalalogueRepository
{
void Create(string guid, string fileName);
}
public class CalalogueRepository : ICalalogueRepository
{
private CatalogueContext _catalogueContext;
public CalalogueRepository(CatalogueContext catalogueContext)
{
_catalogueContext = catalogueContext;
}
public void Create(string guid, string fileName)
{
_catalogueContext.Catalogues.Add(new Catalogue
{
CatalogueId = guid,
FileName = fileName
});
}
}
StuffRepo:
public interface IStuffRepo
{
void Create(string guid, List<StuffModel> myStuff);
}
public class StuffRepo : IStuffRepo
{
private CatalogueContext _catalogueContext;
public StuffRepo(CatalogueContext catalogueContext)
{
_catalogueContext = catalogueContext;
}
public void Create(string guid, List<StuffModel> myStuff)
{
//add stuff to _catalogueContext.StuffTable.Add
}
}
Finally a class that does the SaveChanges and Commit:
public class UOW : IUOW
{
private CatalogueContext _catalogueContext;
private ICalalogueRepository _calalogueRepo;
private IStuffRepo _stuffRepo;
public UOW(CatalogueContext catalogueContext,
ICalalogueRepository calalogueRepo,
IStuffRepo stuffRepo)
{
_catalogueContext = catalogueContext;
_calalogueRepo = calalogueRepo;
_stuffRepo = stuffRepo;
}
public void Save (string guid, string fileName, List<StuffModel> myStuff)
{
using (IDbContextTransaction transection = _catalogueContext.Database.BeginTransaction())
{
_calalogueRepo.Create(guid, fileName);
_stuffRepo.Create (guid, myStuff);
_catalogueContext.SaveChanges();
transection.Commit();
}
}
}
I think there is only 1 CatalogueContext throughout the call.
Ok, so as you can see here, AddDbContext is the right way to register it as you wrote in the comment on the question.
Here it says that AddDbContext will register the context as scoped.
And here you can find what scoped means.
Overall I think you are right that your code will use the same context throughout the Save method.
Couple thoughts:
Probably you want to have a try-catch in case an exception is thrown and you want to rollback
If you are not sure if it's working why not try it? You should test your code/application anyways.
Probably this could be done in a better way, but I don't have the context about the rest of your code/application, so I cannot tell. (Not sure what you mean by "...Unit of work pattern, but that will require me to do a lot of changes." for example.)
Now the Create methods not self-contained, meaning if you just want to add a new item to the table it is not enough to call Create, but separately call SaveChanges(). This is not an explicit problem, but has to be kept in mind and might be a little bit confusing for new developers on the project.
Normally I do my data access by instanciating my DbContext globally in my Controller and then I use that manipulate my data.
See below:
public class UserController : Controller
{
private OrtundEntities db = new OrtundEntities();
public ActionResult Create(CreateUserViewModel model)
{
try
{
UserDataModel user = new UserDataModel
{
// map view model fields to data model ones
};
db.Users.Add(user);
db.SaveChanges();
}
catch (Exception ex)
{
// some or other error handling goes here
}
}
}
It occurs to me that this might not be the ideal way to do it in all applications but aside from implementing a web service for every project I do, I can't think of any alternatives to the above.
So what's a better way to handle the data access on larger projects where the above wouldn't be ideal?
I'm just looking for so-called "best practice" for this or that particular situation. Many opinions will differ on what's the best way so what do you think it is and why?
To help keep your controllers concise and free of direct access to your database, you can implement the repository and dependency injection patterns. For even more concise code, you can also use the unit of work pattern.
Say you had this model:
public class Person {
public int Id { get; set; }
public string Name { get; set; }
}
With the help of generics, you can create an interface to provide a CRUD blueprint:
public interface IRepository<T> {
IEnumerable<T> Get();
T Get(int? i);
void Create(T t);
void Update(T t);
void Delete(int? i);
}
Then create a Repository class that implements the IRepository. This is where all your CRUD will take place:
public class PersonRepository : IRepository<Person> {
private OrtundEntities db = new OrtundEntities();
public IEnumerable<Person> Get() {
return db.Persons.ToList();
}
//invoke the rest of the interface's methods
(...)
}
Then in your controller you can invoke the dependency injection pattern:
private IRepository<Person> repo;
public PersonController() : this(new PersonRepository()) { }
public PersonController(IRepository<Person> repo) {
this.repo = repo;
}
And your controller method for, say, Index() could look like this:
public ActionResult Index() {
return View(repo.Get());
}
As you can see this has some useful benefits, including structure to your project, and keeping your controllers easy to maintain.
I think you need to read this
http://chsakell.com/2015/02/15/asp-net-mvc-solution-architecture-best-practices/
Larger proyets ?
Maybe https://msdn.microsoft.com/es-es/library/system.data.sqlclient.sqlcommand(v=vs.110).aspx
I use this in some big requests.
I am tasked with pulling all the rows from a 3rd party vendor's SQLite data table, creating business objects from those records, and sending the new business objects off to another class.
Pseudo-code:
var databasePath = "%user profile%\application data\some3rdPartyVendor\vendor.sqlite"
var connection = OpenSqliteConnection(databasePath);
var allGizmoRecords = connection.Query(...);
var businessObjects = TransformIntoBizObjs(allGizmoRecords);
someOtherClass.HandleNewBizObjs(businessObjects);
I've got all that working.
My question is: How can I write this class so it's unit testable?
Should I:
use the repository pattern to mock out the data access
actually provide a dummy SQLite database in the unit test
Or any better ideas? I'm using C#, but this question seems rather language-agnostic.
You could inject a test-only Sqlite database quite easily, refactoring the code to look like below. But how are you asserting the results? The business objects are passed to someOtherClass. If you inject an ISomeOtherClass, that class's actions need to be visible too. It seems like a bit of pain.
public class KillerApp
{
private String databasePath;
private ISomeOtherClass someOtherClass;
public KillerApp(String databasePath, ISomeOtherClass someOtherClass)
{
this.databasePath = databasePath;
this.someOtherClass = someOtherClass;
}
public void DoThatThing()
{
var connection = OpenSqliteConnection(databasePath);
var allGizmoRecords = connection.Query(...);
var businessObjects = TransformIntoBizObjs(allGizmoRecords);
someOtherClass.HandleNewBizObjs(businessObjects);
}
}
[TestClass]
public class When_Doing_That_Thing
{
private const String DatabasePath = /* test path */;
private ISomeOtherClass someOtherClass = new SomeOtherClass();
private KillerApp app;
[TestInitialize]
public void TestInitialize()
{
app = new KillerApp(DatabasePath, someOtherClass);
}
[TestMethod]
public void Should_convert_all_gizmo_records_to_busn_objects()
{
app.DoThatThing();
Assert.AreEqual(someOtherClass.Results, /* however you're confirming */);
}
}
Using an IRepository would remove some of the code from this class, allowing you to mock the IRepository implementation, or fake one just for test.
public class KillerApp
{
private IRepository<BusinessObject> repository;
private ISomeOtherClass someOtherClass;
public KillerApp(IRepository<BusinessObject> repository, ISomeOtherClass someOtherClass)
{
this.repository = repository;
this.someOtherClass = someOtherClass;
}
public void DoThatThing()
{
BusinessObject[] entities = repository.FindAll();
someOtherClass.HandleNewBizObjs(entities);
}
}
[TestClass]
public class When_Doing_That_Thing
{
private const String DatabasePath = /* test path */;
private IRepository<BusinessObject> repository;
private ISomeOtherClass someOtherClass = new SomeOtherClass();
private KillerApp app;
[TestInitialize]
public void TestInitialize()
{
repository = new BusinessObjectRepository(DatabasePath);
app = new KillerApp(repository, someOtherClass);
}
[TestMethod]
public void Should_convert_all_gizmo_records_to_busn_objects()
{
app.DoThatThing();
Assert.AreEqual(someOtherClass.Results, /* however you're confirming */);
}
}
But this still feels quite cumbersome. There are two reasons, 1) the Repository pattern has been getting some bad press lately from Ayende, who knows a thing or two about Repository. And 2) what are you doing writing your own data access!? Use NHibernate and ActiveRecord!
[ActiveRecord] /* You define your database schema on the object using attributes */
public BusinessObject
{
[PrimaryKey]
public Int32 Id { get; set; }
[Property]
public String Data { get; set; }
/* more properties */
}
public class KillerApp
{
private ISomeOtherClass someOtherClass;
public KillerApp(ISomeOtherClass someOtherClass)
{
this.someOtherClass = someOtherClass;
}
public void DoThatThing()
{
BusinessObject[] entities = BusinessObject.FindAll() /* built-in ActiveRecord call! */
someOtherClass.HandleNewBizObjs(entities);
}
}
[TestClass]
public class When_Doing_That_Thing : ActiveRecordTest /* setup active record for testing */
{
private ISomeOtherClass someOtherClass = new SomeOtherClass();
private KillerApp app;
[TestInitialize]
public void TestInitialize()
{
app = new KillerApp(someOtherClass);
}
[TestMethod]
public void Should_convert_all_gizmo_records_to_busn_objects()
{
app.DoThatThing();
Assert.AreEqual(someOtherClass.Results, /* however you're confirming */);
}
}
The result is a much smaller class and a business object and data-layer that you can change more easily. And you don't even have to mock the database calls, you can configure and initialize ActiveRecord to use a test database (in-memory, even).
Well, the only thing that would really need to be tested here is TransformIntoBizObjs, I would think, since the connection code should have been written/tested elsewhere. Simply passing things that might show up to Transform and seeing if the right thing pops out would be what you need to do.
Remember to test all usecases of Transform, even potentially weird items that probably shouldn't end up in the function call, but might. Never know what people have been shoving in their databases.
Inversion of Control (IoC) and Dependency Injection (DI) will go a long way towards making your code more testable. There are a lot of frameworks out there that can assist you with this, but for your purposes you don't necessarily need to go to all that effort.
Start with extracting an interface that might look something like this:
Interface ISqlLiteConnection
{
public IList<GizmoRecord> Query(...);
}
Once you've done that, you should refactor the OpenSqlLiteConnection() method to return an instance of ISqlLiteConnection, rather than the concrete implementation. To test, just create a class that implements your interface, which mocks up the actual DB queries and connections with determinate results.
Databases are complicates, you need to test your query code and you need to test it against a real sqlite instance - otherwise you can't be sure you didn't hit some rare sqlite quirk or bug.
And since the only way to test your query is to run it on a real sqlite file, and it's really easy to include such a file with your test there's no point to adding another layer just to make it "more" testable or to have "pure" unit tests.
Just make sure to add all the strange edge cases you can think of to your sample file.