Generic DAL / BLL Classes - c#

I'm currently building the Data Access Layer and Business Logic Layer classes for our new application, and I have a question (obviously). First, here are some details that may help:
Using Entity Framework 5 for Model classes and data access
Each "layer" is separated in different class libraries and namespaces (i.e App.Model, App.DAL, App.BLL)
Starting with the DAL - I decided to write a base class for all DAL classes to inherit.
public abstract class DALBase<T> : IDisposable
{
protected AppEntities context;
protected DbSet set;
public DALBase()
{
context = new OECCORPEntities();
set = context.Set(typeof(T));
}
protected virtual void Save()
{
context.SaveChanges();
}
public virtual void Add(T model)
{
set.Add(model);
Save();
}
public virtual T Get(int id)
{
return (T)set.Find(id);
}
public virtual List<T> GetAll()
{
return set.OfType<T>().ToList();
}
public virtual void Delete(int id)
{
T obj = Get(id);
set.Remove(obj);
Save();
}
public virtual void Update()
{
Save();
}
public void Dispose()
{
context.Dispose();
}
}
As you will see, the base class implements a generic type which should be the type of the model the DAL class is responsible for working with. Using the generic type, in the constructor it creates a DbSet using the type of the generic argument - which is used in the predefined CRUD-like virtual functions below (add, get, etc).
And then I got the idea - wait a minute... since it's generic, I really don't have to implement DAL classes for every single model. I can just write something like this:
public class GenericDAL<T> : DALBase<T>
{
public GenericDAL() : base() {}
}
... that I can use for any of the models. OK, so on to the Business Logic Layer. I created a base class for BLL as well:
public abstract class BLLBase<T>
{
protected GenericDAL<T> dal;
public BLLBase()
{
dal = new GenericDAL<T>();
}
public virtual void Add(T model)
{
dal.Add(model);
}
public virtual T Get(int id)
{
return dal.Get(id);
}
public virtual List<T> GetAll()
{
return dal.GetAll();
}
public virtual void Delete(int id)
{
dal.Delete(id);
}
public virtual void Update()
{
dal.Update();
}
}
... which uses the GenericDAL to do its work. So in a simular fashion, I just wrote a GenericBLL class that looks like this:
public class GenericBLL<T> : BLLBase<T>
{
public GenericBLL() : base() { }
}
And to test it, a simple console application:
class Program
{
static void Main(string[] args)
{
GenericBLL<ADMIN> bll = new GenericBLL<ADMIN>();
List<ADMIN> admins = bll.GetAll();
}
}
... where "ADMIN" is the model type. Works like a charm.
The idea behind this was to avoid having to write DAL / BLL classes for every single model, unless it needed extra functionality. Can someone tell me why I WOULDN'T want to do it this way? I think the generic DAL / BLL classes would get the job done and also save development time.
Thank you for your time.

Well, one drawback is that if you decide to add some business rules later on you would have to switch the type from GenericBLL[Whatever] to WhateverBLL.
An obvious solution to this is to create a class that inherits from GenericBLL[Whatever]. Like:
public class WhateverBLL : GenericBLL<Whatever>
and use this class instead.

Right now, your BLL isn't particularly adding value. Every call is simply a pass-through to another layer. Maybe it's the simplicity of your application (and thank your lucky stars that you are so lucky), or maybe you have what I would classify as the actual business logic living elsewhere.
Business logic to me is everything that is done up to the point of persisting data, everything that is done after retrieving data, and things like that. The decisions, the forks in the road, the actions that are taken. Actually saving and retrieving data is typical extremely trivial by comparison.
So as I look at your generic DAL base class, I think it's a fine start. I would probably extract an interface from it so I could replace it when testing. For now, your class that inherits the base isn't adding any value. Do not create layers and classes simply for the sake of it, be sure it adds value and makes your life easier in some way.
As I look at your generic BLL class, I think you probably have your real business logic tucked away in the codebehind on some form, or inside a class file in a console app. While it's certainly possible that there could be generically applicable functionality that only varies on the type, I don't think one class is where you want to be. My suggestion here is to reconsider what you think is your actual business logic. A simple pass-through layer to the DAL probably isn't it.

Related

Ioc with service class calling generic method

I having a bit of trouble getting my head around Ioc and generics, and particularly how my company has set up the layers in relation to this. We're working under an MVP architecture.
I have a Car class:
class Car : ICar
{
IList<IWheel> wheels{get;set;}
IEngine engine{get;set;}
string registrationplate {get;set;}
public Car(){}
}
and I want to be able to get a newly created ICar, and I also want to be able to find an ICar by Id. Problem is I'm not sure why some of the design choices have been made in the project I'm working on. The structure for other services already created is as follows:
I have a Car and WHeel Service :
class WheelService : BaseService
{
IWheel wheel;
public IWheel Create()
{
return new wheel()
}
}
class CarService : BaseService
{
WheelService wheelservice;
public ICar CarCreate()
{
wheelservice = new Wheelservice()
car = new Car();
IWheel wheel = wheelservice.Create();
car.wheels.add(wheel);
return car;
}
public ICar Find(int id)
{
return (Car)base.Find<Car>(id);
}
}
Firstly, I'm finding the 'have a service for each entity' odd. I wouldn't have thought that a weak entity would have a service. My thoughts would be that the CarService create method would act like a factory method, without having to call a wheel service.
Also, the wheel service create method is actually used in the presenter code to return an IWheel all the way down to the UI, so that values can be set and passed back up. Again this, seems odd to me. Means the presenter can request the full ICar object from the UI.
Is the dependency in the Service create method normal? I would have thought that this would be brought in through IoC. But, if the ICar Create method was to handle all creation (including wheel, etc), then presumably the container would contain lots of interfaces in relation to this particular service?
If I were to bring in the interfaces, I would need to adjust the CarService.Find method, which is currently using concrete classes. It uses the BaseService, and it is solely this layer which interacts with the container to get the correct repository:
class BaseService
{
private object myRepository;
protected T GetRepository<T>(Type serviceType)
{
if (myRepository == null)
{
myRepository = (T)IoCRepositoryFactory.GetRepositoryInstance(typeof(T), serviceType);
}
return (T)myRepository;
}
protected virtual IGenericRepository Repository
{
get
{
return GetRepository<IGenericRepository>(this.GetType());
}
}
protected virtual T Find<T>(Object id) where T : class
{
return (T)Repository.GetByID<T>(id);
}
}
I'm unsure how to call this find method if I'm only using interfaces, since the current service definition is using concrete classes.
Apologies about this being a long winded post. I've been looking over this for three days, but I need to know what others think of the current set up, and whether I should be using IOC for domain objects in service layer, or whether I should follow the current set up. It just all feels a bit coupled for me at the moment.
There's a lot you're misunderstanding I think.
I'll start with the service structure. You don't have to have each service only handling 1 type of entity, but there's nothing wrong with that as long as it doesn't get in the way of efficiency. Your example is likely unreasonably simplistic, so you probably could have CarService handle Wheel management without any future maintenance issues, but it's common to divide services up by entity and although it often requires some exceptions it usually works fine.
The IoC code you have written is all sorts of wrong though. The goal of IoC is to keep all the code that will be doing your dependency management in a single place that's sort of out of the way. Your code has CarService instantiating WheelService explicitly, while that should be handled by your IoC container. Also, having a GetRepository method is very awkward, and also should be handled automatically by your IoC container.
One way you could setup your services and repositories would be like this (if you're using constructor injection). This is just an example (and a verbose one at that), don't go copying this structure into your own code without fully understanding it.
public interface IRepository {
//Some interfaces
//This method could only really be implemented if you are using an ORMapper like NHibernate
public T FindById<T>(Object id) { }
}
public class BaseRepository : IRepository {
//Some base crud methods and stuff. You can implement this if you're using an ORMapper
public T FindById<T>(Object id)
{
return CurrentSession.FindById<T>(id);
}
}
public class WheelRepository : BaseRepository {
//Wheel crud
//If you don't have an ORMapper because you're a masochist you can implement this here
public Wheel FindById(Object id) { }
}
public class CarRepository : BaseRepository {
//Car crud
//If you don't have an ORMapper because you're a masochist you can implement this here
public Car FindById(Object id) { }
}
public class BaseService {
protected BaseRepository _baseRepository;
//This constructor is automatically called by your IoC container when you want a BaseService
public BaseService(BaseRepository repository)
{
_baseRepository = repository;
}
//More methods
}
public class WheelService : BaseService
{
protected WheelRepository _wheelRepository;
public WheelService(WheelRepository wheelRepo) : base(wheelRepo)
}
public class CarService : BaseService
{
protected WheelService _wheelService;
protected CarRepository _carRepository;
public CarService(WheelService wheelService, CarRepository carRepository)
{
_wheelService = wheelService;
_carRepository = carRepository;
}
}
Since you're using MVP, I assume some kind of WPF/Winforms app, although I suppose you could do a web app as well if you really wanted to make it fit in asp.net. In either case, they both have a single Factory you can configure for creating your presenter classes. In that factory, you'd have it do all the injection there, out of the way in a spot you never have to worry about or even look at after setting it up. That code would just call this:
//Override the default factory method (just made this up)
public override Presenter GetPresenter(Type presenterType)
{
return ComponentFactory.GetInstance(presenterType);
}
Then if you had a presenter that depended on a service, it would automatically be there, and everything that service needs would be there too. Notice how there's no ugly service constructors or factory calls anywhere else. All the dependencies are automagically setup by the container.
I don't know why the code at your company has those awful GetRepository methods. That's an instance of an anti-pattern, because you're replacing what would normally be a constructor call like new Repository() with a GetRepository call instead that's only marginally more maintainable.
You should try playing around with some well-known containers. Structuremap is a pretty good one.

Letting only the abstract class know about its inheritors

I am making a payment system for my site. Users can select one of several payment providers to pay, but all should behave in the same way. I thought to represent this behavior like this:
public abstract class PaymentProvider {
private static var methods = Dictionary<String,PaymentProvider>
{
{"paypal",new PaymentProviderPaypal()},
{"worldpay",new PaymentProviderWorldpay()}
}
public static Dictionary<String,PaymentProvider> AllPaymentProviders
{
get {return methods;}
}
public abstract pay();
}
public class PaymentProviderPaypal : PaymentProvider {
public override pay() {
}
}
public class PaymentProviderWorldpay : PaymentProvider {
public override pay() {
}
}
You are supposed to use this by writing PaymentProvider.AllPaymentProviders["key"].pay(). The idea is that the functions using this class don't need to know about how the underlying payment provider is implemented, they just need to know the key.
However, at the moment, if you have access to the PaymentProvider class, you also have access to the inheriting classes. Its possible to instantiate a new copy of the inheriting classes, and make use of them in an unexpected way. I want to encapsulate the inheriting classes so that only the abstract PaymentProvider knows about them.
How should I do this? Different protection levels like protected don't work here - In Java, protected means that only other classes in the namespace can use that class, but in C# it means something else.
Do I have the right idea here? Or should I use a different method?
A couple of options spring to mind:
Put this in a separate assembly from the client code, and make the implementations abstract
Put the implementations inside the PaymentProvider class as private nested classes. You can still separate the source code by making PaymentProvider a partial class - use one source file per implementation
The first option is likely to be the cleanest if you don't mind separating the clients from the implementation in terms of assemblies.
Note that both of these are still valid options after the change proposed by Jamiec's answer - the "visibility" part is somewhat orthogonal to the inheritance part.
(As an aside, I hope the method is really called Pay() rather than pay() :)
Your inheritance heirachy is a bit wonky, I would be tempted to do it a similar but crucially different way.
public interface IPaymentProvider
{
void Pay()
}
// Implementations of IPaymentProvider for PaypalPaymentProvider & WorldpayPaymentProvider
public static class PaymentHelper
{
private static var providers = Dictionary<String,IPaymentProvider>
{
{"paypal",new PaymentProviderPaypal()},
{"worldpay",new PaymentProviderWorldpay()}
}
public static void Pay(string provider)
{
if(!providers.Containskey(provider))
throw new InvalidOperationException("Invalid provider: " + provider);
providers[provider].Pay();
}
}
Then the usage would be something like PaymentHelper.Pay("paypal").
Obviously if there is more data to provide to the Pay method this can be added to both the interface, and the helper. for example:
public interface IPaymentProvider
{
void Pay(double amount);
}
public static void Pay(string provider, double amount)
{
if(!providers.Containskey(provider))
throw new InvalidOperationException("Invalid provider: " + provider);
providers[provider].Pay(amount);
}

Creating a Generic Save() Method for Models

I have a fairly simple system, and for the purposes of this question there are essentially three parts: Models, Repositories, Application Code.
At the core are the models. Let's use a simple contrived example:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
In that same project is a generic repository interface. At its simplest:
public interface IRepository<T>
{
T Save(T model);
}
Implementations of that interface are in a separate project and injected with StructureMap. For simplicity:
public class PersonRepository : IRepository<Person>
{
public Person Save(Person model)
{
throw new NotImplementedException("I got to the save method!");
// In the repository methods I would interact with the database, or
// potentially with some other service for data persistence. For
// now I'm just using LINQ to SQL to a single database, but in the
// future there will be more databases, external services, etc. all
// abstracted behind here.
}
}
So, in application code, if I wanted to save a model I would do this:
var rep = IoCFactory.Current.Container.GetInstance<IRepository<Person>>();
myPerson = rep.Save(myPerson);
Simple enough, but it feels like it could be automated a lot. That pattern holds throughout the application code, so what I'm looking to do is create a single generic Save() on all models which would just be a shorthand call to the above application code. That way one would need only call:
myPerson.Save();
But I can't seem to figure out a way to do it. Maybe it's deceptively simple and I'm just not looking at it from the correct angle. At first I tried creating an empty ISaveableModel<T> interface and intended to have each "save-able" model implement it, then for the single generic Save() method I would have an extension on the interface:
public static void Save<T>(this ISaveableModel<T> model)
{
var rep = IoCFactory.Current.Container.GetInstance<IRepository<T>>();
model = rep.Save(model);
}
But it tells me that rep.Save(model) has invalid arguments. It seems that it's not wiring up the type inference as I'd hoped it would. I tried a similar approach with a BaseModel<T> class from which models would inherit:
public class BaseModel<T>
{
public void Save()
{
this = IoCFactory.Current.Container.GetInstance<IRepository<T>>().Save(this);
}
}
But the compiler error is the same. Is there a way to achieve what I'm trying to achieve? I'm very flexible on the design, so if I'm going about something all wrong on an architectural level then I have room to step back and change the big picture.
Would a generic extension method solve it?
public static T Save<T>(this T current)
{
var rep = IoCFactory.Current.Container.GetInstance<IRepository<T>>();
rep.Save(current);
}
You can then constrain it to your ISaveableModel<T> interface. Return type above not implemented, but you can put it to a boolean or status flag, whatever.
In both approaches, the parameter to the Save() function is not of type T. In the first one, it is ISaveableModel<T>, and in the second, it is BaseModel<T>. Since the repository is a generic based on T, Save method will expect a variable of type T. You can add a simple cast to T before you call Save to fix it.
Alternatively, your IRepostory<T> can be changed to
public interface IRepository<T>
{
T Save(ISaveableModel<T> model);
}
which makes more sense.

Implementing a CRUD using an Interface

What is the best approach to implement a CRUD on the BL using interface that will be used to abstract DAL operations? I need your opinion guys..
Here's my draft..
Data Entities that are mapped in the database table
public class Student
{
public string StudentId { get; set; }
public string StudentName { get; set; }
public Course StudentCourse { get; set; }
}
public class Course
{
public string CourseCode { get; set; }
public string CourseDesc { get; set; }
}
I created an CRUD Interface to abstract the object's operations
public interface IMaintanable<T>
{
void Create(T obj);
T Retrieve(string key);
void Update(string key);
void Delete(string key);
}
And then a component that manages the Entity and its operations by implementing the interface
public class StudentManager : IMaintainable<Student>
{
public void Create(Student obj)
{
// inserts record in the DB via DAL
}
public Student Retrieve(string userId)
{
// retrieveds record from the DB via DAL
}
public void Update()
{
// should update the record in the DB
}
public void Delete(string userId)
{
// deletes record from the DB
}
}
sample usage
public void Button_SaveStudent(Event args, object sender)
{
Student student = new Student()
{
StudentId = "1", StudentName = "Cnillincy"
}
new StudentManager().Create(student);
}
as you can see, there is quite an abnormalities on the update method
public void Update()
{
// should update the record in the DB
}
what should this method have to update the objects property? should I inherit the Student?
public class StudentManager : Student , IMaintainable<Student>
{
public void Update()
{
//update record via DAL
}
}
public void Button_SaveStudent(Event args, object sender)
{
Student student = new StudentManager();
student.StudentId = "1";
student.StudentName = "Cnillincy"
student.Update()
}
Or should I just contain the Student class as an attribute of the Student manager?
public class StudentManager : IMaintainable<Student>
{
public Student student { get; private set };
public void Create() {}
public void Update() {}
public void Retrieve() {}
public void Delete() {}
}
Which more appropriate? What about the interface? Any other suggestions guys? thanks..C
Your CRUD interface should probably look like
public interface IMaintanable<T>
{
string Create(T obj);
T Retrieve(string key);
void Update(T obj);
void Delete(string key);
}
that is, both Create and Update take a copy of the object you're updating. The difference is that the Update can get the key from the obj, so it knows which object it's changing. Create would normally cause the key to be created so you pass it back as a return value. Hope that helps.
(The Update might also pass back the key too.)
Personally, I think that all you are missing is the appropriate terminology. What this really is an approximation of a very helpful pattern, called the repository pattern. As far as type-awareness, goes, the implementation would be referred to as a generic repository.
The way I have personally implemented in the past was to have an interface defining the repository, such as IRepository<T>, and a base class that is specific to the type of repository, such as a SqlRepositoryBase<T>. The reason that I would do this is that I can put the implementation-specific code in the base class. So, the plumbing is done and I can worry about domain-specific implementation in the final repository, which would be StudentRepository, a SqlRepository<Student> (or SqlRepository<IStudent> if you define interfaces for your entity).
It seems that you are concerned about how many objects are instansiated, and I can tell you that you are not generating a significant enough drain on resources to really be concerned about implementing in this fashion. Old-timers might cringe at the fact, but we are not trying to optimize for 64k or RAM anymore. ;-) It is more about maintainability, code contracts, etc.
Not to add uneeded complexity up-front, but you also might want to look into the Unit of Work Pattern if you are looking at enlisting multiple entities of different types into atomic transactions.
Here are a couple of good references for these topics:
new Repository().DoMagic()
The Unit of Work Pattern
Two takeaways from this in general (IMHO):
I personally disagree with the assumption that a Repository pattern approach only has usefulness in larger projects; especially the Generic Repository pattern. If you start putting code like this into a reusable library, you will be surprised at how quickly you can start creating an invaluable resource of building blocks.
The biggest plus from this approach is the sheer testability of it; even more so than the reusability. If you are looking to mock out your repositories for any sort of a TDD approach, you can do so with little effort. This will allow you to write richer tests around the usages of the repositories throughout your code.
I saw this from Rob Conery that I really like. It's power is in the flexibility of the arguments you can pass to the methods. Your implimentation isn't robust enough IMO. Check out his MVC starter kit here http://mvcstarter.codeplex.com/ (It's called ISession there).
public interface IMaintainable : IDisposable
{
T Single<T>(Expression<Func<T, bool>> expression) where T : class, new();
System.Linq.IQueryable<T> All<T>() where T : class, new();
void Add<T>(T item) where T : class, new();
void Update<T>(T item) where T : class, new();
void Delete<T>(T item) where T : class, new();
void Delete<T>(Expression<Func<T, bool>> expression) where T : class, new();
void DeleteAll<T>() where T : class, IEntity, new();
void CommitChanges();
}
I wouldn't make StudentManager inherit Student, I would make my Update method stateless like your create method, i.e.
public interface IMaintanable<T>
{
void Create(T obj);
T Retrieve(string key);
void Update(T obj);
void Delete(string key);
}
and
public void Update(T obj)
{
// should update the record in the DB
}
Take a look at the new Entity Framework 4 that was recently released. They are featuring a "code by convention" model that allows you to easily map your business objects directly to the database without having to worry about a DAL.
"The Gu" has a great series outlining how easy it is to map your objects, and even do some simple modifications when linking to the database through the DbContext model it uses.
It is worth noting that the current release is at CTP4, but I anticipate most of the issues have already been worked out with the framework and should serve you well.
I changed the responses here a little bit, to this:
public interface IMaintanable<T>
{
Guid Create(T obj);
T Read(Guid key);
bool Update(T obj);
bool Delete(Guid key);
}
This interface is based on my database structure. I use Guids for primary keys.

Is a Multi-DAL Approach the way to go here?

Working on the data access / model layer in this little MVC2 project and trying to think things out to future projects.
I have a database with some basic tables and I have classes in the model layer that represent them. I obviously need something to connect the two. The easiest is to provide some sort of 'provider' that can run operations on the database and return objects.
But this is for a website that would potentially be used "a lot" (I know, very general) so I want to cache results from the data layer and keep the cache updated as new data is generated.
This question deals with how best to approach this problem of dual DALS. One that returns cached data when possible and goes to the data layer when there is a cache miss. But more importantly, how to integrate the core provider (thing that goes into database) with the caching layer so that it too can rely on cached objects rather than creating new ones.
Right now I have the following interfaces:
IDataProvider is used to reach the database. It doesn't concern itself with the meaning of the objects it produces, but simply the way to produce them.
interface IDataProvider{
// Select, Update, Create, et cetera access
IEnumerable<Entry> GetEntries();
Entry GetEntryById(int id);
}
IDataManager is a layer that sits on top of the IDataProvider layer and manages the cache
interface IDataManager : IDataProvider{
void ClearCache();
}
Note that in practice the IDataManager implementation will have useful helper functions to add objects to their related cache stores. (In the future I may define other functions on the interface)
I guess what I am looking for is the best way to approach a loop back from the IDataProvider implementations so that they can access the cache. Or a different approach entirely may be in order? I am not very interested in 3rd party products at the moment as I am interested in the design of these things much more than this specific implementation.
Edit: I realize the title may be a bit misleading. I apologize for that... not sure what to call this question.
Personally, I currently use NHibernate which handles caching for you. In the past, I have done something similar to what you are trying to do, however I never had need to separate the caching layer from the dao layer. Is there some reason that you need to separate these? I suppose it would make sense if you have significantly different caching needs dependent on the object type. Anyway, assuming that it is necessary, here is how I would go about doing it based on past experience. Firstly, lets assume we have the following classes: PersistentObject, which is a base object that has at least an integer property called "ID"
public class PersistentObject
{
public int ID { get; set; }
}
Now say you have a sample type that you would like to persist:
public class SampleObject : PersistentObject
{
public string SomeValue { get; set; }
}
In place of "DataProvider", I have a simple repository interface:
public interface IRepository<T> where T : PersistentObject
{
T Get(int id);
void Save(T e);
void Delete(T e);
}
How about, instead of your IDataManager interface, you have an abstract class that you can implement that is a repository that handles caching (I have my own "CacheManager" class that I'm using here, it could be implemented any number of ways):
public abstract class CacheRepository<T> : IRepository<T> where T : PersistentObject
{
private const string CacheKeyPrefix = "RepoCache-";
private string GetCacheKey(int id)
{
return CacheKeyPrefix + typeof(T).FullName + "-" + id.ToString();
}
public T Get(int id)
{
string cacheKey = GetCacheKey(id);
T obj = CacheManager.GetItemFromCache<T>(cacheKey);
if (obj == null)
{
obj = this.GetData(id);
if (obj != null)
CacheManager.AddItemToCache(obj, cacheKey);
}
return obj;
}
public void Save(T obj)
{
string cacheKey = GetCacheKey(obj.ID);
this.SaveData(obj);
CacheManager.AddItemToCache(obj, cacheKey);
}
public void Delete(T obj)
{
string cacheKey = GetCacheKey(obj.ID);
this.DeleteData(obj);
CacheManager.RemoveItemFromCache(cacheKey);
}
protected abstract T GetData(int id);
protected abstract void SaveData(T obj);
protected abstract void DeleteData(T obj);
}
You'll notice that the only members that are publicly exposed are the methods that implement IRepository. There are 3 abstract methods that must be implemented for data access by the individual repository. So we can do that here for our SampleObject:
public class SampleObjectRepository : CacheRepository<SampleObject>
{
protected override SampleObject GetData(int id)
{
//do some loading
return new SampleObject();
}
protected override void SaveData(SampleObject obj)
{
//do some saving
}
protected override void DeleteData(SampleObject obj)
{
//do some deleting
}
}
Lastly, this is how you would go about utilizing this code:
public class UsageSample
{
public UsageSample()
{
//save a new object
SampleObjectRepository repo = new SampleObjectRepository();
SampleObject sampleObj = new SampleObject();
repo.Save(sampleObj);
//load an object by ID
int id = sampleObj.ID;
sampleObj = repo.Get(id);
//delete an object
repo.Delete(sampleObj);
}
}
It gets significantly more complex when you start to talk about returning collections and querying, but this is at least a simplistic start. Are you sure you're not interested in 3rd party solutions? :-) NHibernate does a pretty great job of handling all of this for you.

Categories

Resources