I have a website and want to step over from MySql to SqlServer.
In my website I use a BE layer (Business Entities), BLL (Business Logic Layer), DAL (Data Access Layer), and of course a Web Layer (Website)
I've created a switch in the web.config (app settings) to tell the website to use MySql or SqlServer as DataProvider.
I use the folowing code.... which works perfectly, but my question is ...
Is this the right way to use a multi DAL tier?
Is this thread Safe ? or I have to implement Singleton at the Factory class ?
Please let me know what you should do, or what your opionion is.
namespace MyNameSpace.BE {
public class Product {
public int Id { get; set; }
public int Description { get; set; }
}
}
namespace MyNameSpace.DAL.Base {
public abstract class ProductManager {
public abstract List<Product> GetProductList();
}
}
namespace MyNameSpace.DAL.MySql {
public class ProductManager : Base.ProductManager {
public override List<Product> GetProductList() {
return new List<Product>();
}
}
}
namespace MyNameSpace.DAL.SqlServer {
public class ProductManager : Base.ProductManager {
public override List<Product> GetProductList() {
return new List<Product>();
}
}
}
namespace MyNameSpace.Bll {
/// do I have to use Singleton here ?? or not ?
public static class Factory {
private static ProductManager CreateProductManager() {
if (Config.Settings.Switches.DataProvider == DataProvider.MySql) {
return new DAL.MySql.ProductManager();
} else if (Config.Settings.Switches.DataProvider ==
DataProvider.SqlServer) {
return new DAL.SqlServer.ProductManager();
}
return null;
}
private static ProductManager _ProductManager;
public static ProductManager ProductManager {
get {
if (_ProductManager == null) {
_ProductManager = CreateProductManager();
}
return _ProductManager;
}
}
}
}
/// <summary>
/// for example ASP.NET page
/// </summary>
class MyPage {
public MyPage() {
List<Product> productList = Factory.ProductManager.GetProductList();
}
}
I recommend that you use an Inversion of Control (IoC) container. One such IoC container can be found in Microsoft Unity.
Related
I have an existing C# console application that takes arguments and based on the arguments
creates an instance of markets (UK, US, MX..) using dependency injection.
Each market class does a 'string GetData()', 'string ProcessData()' and 'bool ExportData()'.
The application was initially created for one eCommerce vendor's markets. Now I am told to modify it for a different vendor that does a different process. The high-level flow remains the same.
'GetData' to fetch records from DB,
'ProcessData' for any transformation or the likes
'ExportData'.
The difference is Getdata() pulls records from DB and maps to an object. I am planning to use Petapoco. 'ProcessData' might return a similar class. 'Exportdata' currently does an API call but for the new vendor, I have to write to a file.
I was reading up on patterns I am totally confused. At first, I thought I needed abstract factory pattern and now I think the factory method is what I should be using but I am not sure if I am doing it right. Need some guidance/review here. A sample cs file I created from my understanding of factory pattern. This code is based on the headfirst code samples.
using System;
using System.Collections.Generic;
using StatusExport.Models;
namespace factorymethod
{
class Program
{
static void Main(string[] args)
{
ClientFactory factory = null;
Console.WriteLine("Enter client code:");
string clientCode= Console.ReadLine();
switch (clientCode.ToLower())
{
case "costco":
factory = new CostcoFactory("accountname", "taskname");
break;
//NEw vendor might be added
//case "walmart"
//factory = new WalmartFactory("taskname", "type");
//break
default:
break;
}
bool status = factory.ProcessData();
Console.ReadKey();
}
}
abstract class Client
{
public abstract string AccountName { get; }
public abstract string Task { get; set; }
//More properties might be added. Some may not even be used by some of the new vendors. For example, Costco Might need accountname and task. Tomorrow if walmart comes, they might not need these two or may need task and a new property 'type'
public abstract List<T> GetData<T>();
public abstract List<T> ProcessData<T>();
public abstract bool ExportData();
}
class CostcoClient : Client
{
public override string AccountName { get; }
public override string Task { get; set; }
public CostcoClient(string accountName, string task)
{
AccountName = accountName;
Task = task;
}
public override List<DBRecord> GetData<DBRecord>() //DBRecord class is specific to Costco.
{
List<DBRecord> dbresult = new List<DBRecord>();
//dbresult = db return data mapped to an object DBRecord using petapoco. Another vendor might have a different class to which DB records are mapped. So the return type can be generic
return asn;
}
public override List<T> ProcessData<T>()
{
throw new NotImplementedException(); //Any data transformation or business logic. Return type might be DBRecord or a new class altogether
}
public override bool ExportData()
{
throw new NotImplementedException();//Call API or write data to file and if success send true else false
}
}
abstract class ClientFactory
{
public abstract bool ProcessData();
}
class CostcoFactory : ClientFactory
{
public string AccountName { get; }
public string Task { get; set; }
public CostcoFactory(string accountname, string task)
{
AccountName = accountname;
Task = task;
}
public override bool ProcessData()
{
CostcoClient gc = new CostcoClient(AccountName, Task);
var result = gc.GetData<DBRecord>();
return true;
}
}
}
Do you think this is the right design approach?
I also want to keep the console project independent of vendor project. So maybe 'StatusExport.Program' for the console application. DLL projects StatusExport.Common to hold the interface and abstract classes' and 'StatusExport.Client(ex:StatusExport.Costco)' for each vendor stuff.
You can create BaseClient class that will contains a basic group of properties, and if you need to add something new - just inherit it. You did right, but i think it's better to change public modifier to protected in your properties AccountName and Task, to give access to them only from child classes.
Actually, you can create a BaseClientModels (request/response) for each method if you are not sure that returning type List will be always actual.
Example:
public abstract class BaseClient
{
#region Properties : Protected
protected abstract string AccountName { get; }
protected abstract string Task { get; set; }
#endregion
#region Methods : Public
public abstract BaseGetDataResponseModel GetData(BaseGetDataRequestModel model);
public abstract BaseProcessDataResponseModel ProcessData(BaseProcessDataRequestModel model);
public abstract BaseExportDataResponseModel ExportData(BaseExportDataRequestModel model);
#endregion
}
public class BaseGetDataResponseModel { }
public class BaseGetDataRequestModel { }
public class BaseProcessDataResponseModel { }
public class BaseProcessDataRequestModel { }
public class BaseExportDataResponseModel { }
public class BaseExportDataRequestModel { }
Then let's look on your class CostcoClient and how it can looks like:
public class CostcoClient : BaseClient
{
#region Properties : Protected
protected override string AccountName { get; }
protected override string Task { get; set; }
protected virtual IDataReader<BaseGetDataRequestModel, BaseGetDataResponseModel> DataReader { get; }
protected virtual IDataProcessor<CostcoClientProcessDataRequestModel, CostcoClientProcessDataResponseModel> DataProcessor { get; }
protected virtual IExportDataHandler<CostcoClientExportDataRequestModel, CostcoClientExportDataResponseModel> ExportDataHandler { get; }
#endregion
#region Constructors
public CostcoClient(string accountName, string task)
{
//set DataReader, DataProcessor, ExportDataHandler
AccountName = accountName;
Task = task;
}
#endregion
#region Methods : Public
public override BaseGetDataResponseModel GetData(BaseGetDataRequestModel model)
{
if (model is CostcoClientGetDataRequestModel clientGetDataRequestModel)
{
return DataReader.ReadData(clientGetDataRequestModel);
}
return null; //wrong type has passed
}
public override BaseProcessDataResponseModel ProcessData(BaseProcessDataRequestModel model)
{
if (model is CostcoClientProcessDataRequestModel clientProcessDataRequestModel)
{
return DataProcessor.ProcessData(clientProcessDataRequestModel);
}
return null;
}
public override BaseExportDataResponseModel ExportData(BaseExportDataRequestModel model)
{
if (model is CostcoClientExportDataRequestModel clientExportDataRequestModel)
{
return ExportDataHandler.Handle(clientExportDataRequestModel);
}
return null;
}
#endregion
}
public class CostcoClientGetDataRequestModel : BaseGetDataRequestModel { }
public class CostcoClientGetDataResponseModel : BaseGetDataResponseModel { }
public class CostcoClientProcessDataRequestModel : BaseProcessDataRequestModel { }
public class CostcoClientProcessDataResponseModel : BaseProcessDataResponseModel { }
public class CostcoClientExportDataRequestModel : BaseExportDataRequestModel { }
public class CostcoClientExportDataResponseModel : BaseExportDataResponseModel { }
public interface IDataReader<TIn, TOut>
{
public TOut ReadData(TIn model);
}
public interface IDataProcessor<TIn, TOut>
{
public TOut ProcessData(TIn model);
}
public interface IExportDataHandler<TIn, TOut>
{
public TOut Handle(TIn model);
}
public class CostcoClientDataReader : IDataReader<CostcoClientGetDataRequestModel, CostcoClientGetDataResponseModel>
{
public CostcoClientGetDataResponseModel ReadData(CostcoClientGetDataRequestModel model)
{
throw new NotImplementedException();
}
}
//and so on
You have to implement IDataReader, IDataProcessor, IExportDataHandler, make your logic and call it from GetData, ProcessData, ExportData methods, as an example, and get instances via dependency injection.
Then, we can change your factory to this:
public interface IClientFactory
{
BaseClient GetClientService(ClientServicesEnum value);
}
public class BaseClientFactory : IClientFactory
{
#region Propertied : Protected
protected virtual IEnumerable<BaseClient> Services { get; }
protected string AccountName { get; }
protected string Task { get; set; }
#endregion
#region Constructors
public BaseClientFactory(IEnumerable<BaseClient> services, string accountname, string task)
{
Services = services;
AccountName = accountname;
Task = task;
}
#endregion
public BaseClient GetClientService(ClientServicesEnum value)
=> Services.First(x => x.GetType().Equals(GetClientServiceByCode()[value]));
private Dictionary<ClientServicesEnum, Type> GetClientServiceByCode()
=> new Dictionary<ClientServicesEnum, Type>()
{
{ ClientServicesEnum.CostcoClient, typeof(CostcoClient) }
};
}
public enum ClientServicesEnum
{
CostcoClient = 1,
Another2 = 2,
Another3 = 3
}
Where
protected virtual IEnumerable<BaseClient> Services { get; }
you can get via DI too, and then get correct ServiceHandler by enum.
And your main function to call all this:
switch (clientCode)
{
case 1:
baseClient = ClientFactory.GetClientService(ClientServicesEnum.CostcoClient);
break;
case 2:
baseClient = ClientFactory.GetClientService(ClientServicesEnum.Another2);
break;
default:
break;
}
bool status = baseClient.ProcessData(null); //your model
The main thing is - you can use more than one pattern, for example one from Creational patterns, and one from Structural.
If i need some help in code architecture i use this:
https://refactoring.guru/
I think, using this example you can remove properties AccountName and Task, because of request models in methods.
I have replaced the AuditingStore with my own so that I can set the CustomData field, and this is working great.
public class MyAuditingStore : AuditingStore
{
public MyAuditingStore(IRepository<AuditLog, long> auditLogRepository)
: base(auditLogRepository)
{
}
public override Task SaveAsync(AuditInfo auditInfo)
{
auditInfo.CustomData = "certain additional data that is not captured by default";
return base.SaveAsync(auditInfo);
}
}
But now I want to know how to inject services into the AuditingStore so that I can retrieve other information during SaveAsync. How is this done?
Similar to how you would inject services elsewhere.
public class MyAuditingStore : AuditingStore
{
private readonly OtherInformationService _otherInformationService;
public MyAuditingStore(
IRepository<AuditLog, long> auditLogRepository,
OtherInformationService otherInformationService)
: base(auditLogRepository)
{
_otherInformationService = otherInformationService;
}
public override Task SaveAsync(AuditInfo auditInfo)
{
auditInfo.CustomData = otherInformationService.GetOtherInformation();
return base.SaveAsync(auditInfo);
}
}
public class OtherInformationService : ITransientDependency
{
public string GetOtherInformation()
{
return "other information";
}
}
I’m trying to create a middle layer that will allow me a to connect to either a Live service or a Test service without making changes to my client.
I need to return a generic object called Product to use in the client. I get this from the middle layer but I don't need to know how I get this or where it's from. The middle layer connects to a live and test service and I just call a method to get the stuff I need.
The problem is returning the product I got from whichever service back to the client. The method is expecting Product but it's trying to send LiveService.Product or TestService.Product.
Is there any way to convert these types into a generic Product type so they can be returned to the client?
Below is what I have created so far.
Client
Connection conn = new Connection("Test");
IServiceImplementation service = conn.GetServiceImplementation();
Product prod = service.GetProductUsingId(123);
Middle Layer
public interface IServiceImplementation
{
Product GetProductUsingId (int productID);
}
public class Connection
{
private string mode;
public Connection(string _Mode)
{
mode = _Mode;
}
public IServiceImplementation GetServiceImplementation()
{
if (mode == "Live")
{
return new LiveService();
}
else if (mode == "Test")
{
return new TestService();
}
else
{
return null;
}
}
}
Public class LiveService : IServiceImplementation
{
public Product GetProductUsingId (int productID)
{
LiveService.Service live = new LiveService.Service();
return live.GetProduct(2638975);
}
}
Public class TestService : IServiceImplementation
{
public Product GetProductUsingId (int productID)
{
TestService.Service test = new TestService.Service();
return test.GetProduct(2638975);
}
}
The easiest answer is to define your own Product class to return.
public class MyProduct
{
//some properties
}
public MyProduct GetProductUsingId (int productID)
{
LiveService.Service live = new LiveService.Service();
var product = live.GetProduct(2638975);
var myProduct = new MyProduct();
//Copy properties
myProduct.SomeProp = product.SomeProp;
//etc
return myProduct;
}
The alternative is to use partial classes. The Product class in each service namespace should already be defined as partial. Create another part of the partial in another file for each service type and inherit an interface:
namespace SomeSharedNamespace
{
public interface IProduct
{
//shared properties you need
}
}
namespace LiveService
{
public partial class Product : IProduct
{
//implement interface
}
}
namespace TestService
{
public partial class Product : IProduct
{
//implement interface
}
}
Now each Product implements the IProduct interface, so return that
public IProduct GetProductUsingId (int productID)
{
LiveService.Service live = new LiveService.Service();
return live.GetProduct(2638975);
}
As you have seen, Product, LiveService.Product, and TestService.Product are three different types and cannot be converted to each other.
If you cannot arrange for the same type to be used, or for LiveService.Product and TestService.Product to inherit from Product, then your next option is to copy the properties from Live(Test)Service.Product to Product.
In my example, I used AutoMapper to copy the property values from the Live(Test)Service.Product to Product.
It is worth mentioning that these are three different types and if any properties of the any of the three types are changed, that could cause problems. With AutoMapper, any property names that don't match will fail to copy, without displaying any error. That could cause you to overlook the fact that a property value is not being passed.
public IServiceImplementation GetServiceImplementation()
{
if (mode == "Live")
{
return new LiveServiceImplementation();
}
else if (mode == "Test")
{
return new TestServiceImplementation();
}
else
{
return null;
}
}
public class LiveServiceImplementation : IServiceImplementation
{
public LiveServiceImplementation()
{
Mapper.CreateMap<LiveService.Product, Product>();
}
public Product GetProductUsingId(int productID)
{
LiveService.Service _service = new LiveService.Service();
return Mapper.Map<LiveService.Product, Product>(_service.GetProduct(2638975));
}
}
public class TestServiceImplementation : IServiceImplementation
{
public TestServiceImplementation()
{
Mapper.CreateMap<TestService.Product, Product>();
}
public Product GetProductUsingId(int productID)
{
TestService.Service _service = new TestService.Service();
return Mapper.Map<TestService.Product, Product>(_service.GetProduct(2638975));
}
}
I have just learned about GraphDiff, and how it is supposed to take care of all the differences between the disconnected entity and the one stored in the database.
The thing is that I do not know how to use GraphDiff, I tried the documentation, but I didn't understand it well.
I am using an abstracted DBContext, through an Interface and using DbSet so I could perform Unit Testing on them:
public interface IDbRepositories
{
IDbSet<Client> ClientsDB { get;}
AppIdentityDbContext DB { get; }
IDbSet<Contacts> ContactsDB { get; }
IDbSet<ExposureResult> ExposureDB { get; }
IDbSet<OrderMods> OrderModsDB { get; }
IDbSet<ProductDetails> ProductDetailsDB { get; }
IDbSet<OrderProcess> OrderProcessDB { get; }
IDbSet<Order> OrderDB { get; }
void SaveChanges();
}
This is the actual class implementing the interface:
public class DbRepositories : IDbRepositories
{
private AppIdentityDbContext db = new AppIdentityDbContext();
//Get DB Context. This is done this way, so a Mock can be injected when testing
public IDbSet<Client> ClientsDB
{
get { return db.Clients; }
}
public AppIdentityDbContext DB
{
get { return db; }
}
public IDbSet<Contacts> ContactsDB
{
get { return db.Contacts; }
}
public IDbSet<ExposureResult> ExposureDB
{
get { return db.ExposureTBL; }
}
public IDbSet<OrderMods> OrderModsDB
{
get { return db.OrderMods; }
}
public IDbSet<ProductDetails> ProductDetailsDB
{
get { return db.ProductDetailsTBL; }
}
public IDbSet<OrderProcess> OrderProcessDB
{
get { return db.OrderProcesses; }
}
public IDbSet<Order> OrderDB
{
get { return db.OrderTBL; }
}
public void SaveChanges()
{
this.db.SaveChanges();
}
}
Now, the problem part is in here:
public bool SaveOrderChanges(OrderProcess[] Order, int OrderID, int uid)
{
//2nd Step:
var ComparableObject = dbs.OrderProcessDB.Where(x => x.OrderID == OrderID).ToList();
var Objections = dbs.OrderDB.Where(x => x.OrderID == OrderID).FirstOrDefault();
dbs.DB.UpdateGraph(dbs.OrderDB, m => m.OwnedCollection());
dbs.SaveChanges();
return true;
}
I'd like to tell the differences between the Order parameter and the one I extract from OrderProcessDB. These are a One to Many Relationship.
I do not know how to use GraphDiff for this scenario. Any ideas?
You could just expose the base DbContext object in the interface, but that would violate basic principles of encapsulation. The challenge is that the UpdateGraph method is a static extension off of the concrete DbContext class. Here is my solution:
First the interface:
public interface IMyDbContext
{
...
TEntity UpdateGraph<TEntity>(TEntity entity, Expression<Func<IUpdateConfiguration<TEntity>, object>> mapping = null) where TEntity : class, new();
}
Then the actual DbContext:
public class MyDbContext : DbContext, IMyDbContext
{
...
public TEntity UpdateGraph<TEntity>(TEntity entity, Expression<Func<IUpdateConfiguration<TEntity>, object>> mapping = null) where TEntity : class, new()
{
return ((DbContext)this).UpdateGraph(entity, mapping);
}
}
And lastly example usage inside of a repository:
public class MyRepository : IMyRepository
{
private readonly IMyDbContext _myDbContext;
public MyRepository (IMyDbContext myDbContext)
{
_myDbContext = myDbContext;
}
public async Task<SomeEntity> UpdateSomeEntity(SomeEntity updatedSomeEntity)
{
_myDbContext.UpdateGraph(updatedSomeEntity, map => map.OwnedCollection(p => p.SomeChildCollection));
await _myDbContext.SaveChangesAsync();
return updatedSomeEntity;
}
}
I realize this is old, but I just found out about GraphDiff and can hopefully help anyone else looking.
This is how you use GraphDiff:
db.UpdateGraph(orderToUpdate, map => map
.AssociatedCollection(t => t.Products)
.OwnedCollection(t => t.PaymentMethods));
This says to update the Order object, and that the Order owns the PaymentMethods (meaning it can actually remove those entities), and is associated with the Products entities (meaning it will remove them from the reference table).
Is there some automated awesomeness that entity framework does that means I do not have to re-write the crud controllers and views to work with my repository and unity framework injection :( ?
It references the entityframework database context explicitly in the controllers... and then does actual data operations inside the controllers themselves...
for example, this ends up in my controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include="ProductID,Title")] Product product)
{
if (ModelState.IsValid)
{
db.Products.Add(product);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(product);
}
when really the .Add and .SaveChanges need to be in my repository...
I don't want to write the 50 CRUD operations or copy and paste views and controllers every time I want to create that stuff... Is there a way of automating
probably something like this:
namespace WebApplication.Domain.Abstract
{
public interface IProductRepository
{
IQueryable<Product> Products { get; }
Product Create(Product product);
... yada yada crud operations
}
}
public class EFProductRepository : IProductRepository
{
private EFDbContext context = new EFDbContext();
public IQueryable<Product> Products
{
get { return context.Products; }
}
//... implements all the CRUD operations that entity framework ends up placing inside the controller
}
Since according to comments this is what has solved the problem:
Visual Studio provides a built-in way for template based code generation. It's called T4 and you can read more about it here.
A generic Repository<TPoco> is the general approach here.
ie 1 Repository reused with for every POCO.
It is also commonly used with a Unit Of Work Pattern to combine updates into a logical unit of work.
Here is a basic Demo to illustrate the point.
BUT IDEALLY an IRepository is declared in a core Layer
and a Data Access layer implements Repositiry:IRepository to keep ef references
out of a core domain layer. (That is another important related code architecture matter to research)
This demo is too short for IRepository<t>
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace repofT
{
class Program
{
static void Main(string[] args)
{
// Kick Start Repository of T demo
// There are advance models combining context creation / unit of work and repository.
// The concept of Inversion of Control / Dependency injection should be inestigated
// for the people new to IOC
// SIMPLIFIED Unit of Work and Respository of T sample
var ctx = new MyContext();
var uow = new UnitOfWork(ctx);
var rep = new Repository<MyPoco>(ctx);
addTest(rep, uow);
var poco1 = FindTest(rep);
ChangeTest(poco1, rep, uow);
Console.ReadKey();
}
private static void ChangeTest(MyPoco poco1, Repository<MyPoco> rep, UnitOfWork uow)
{
poco1.Content = "Test - was changed";
rep.Change(poco1);
uow.Commit();
DumpTest(rep);
}
private static MyPoco FindTest(Repository<MyPoco> rep)
{
var poco1 = rep.Find(1);
Console.WriteLine(poco1.Id + " : " + poco1.Content);
return poco1;
}
private static void addTest(Repository<MyPoco> rep, UnitOfWork uow)
{
var mypoco = new MyPoco()
{
Content = "Test" + System.DateTime.Now.ToString(CultureInfo.InvariantCulture),
};
rep.Add(mypoco);
uow.Commit();
DumpTest(rep);
}
private static void DumpTest(Repository<MyPoco> rep)
{
var pocoList = rep.GetList(t => t.Content.StartsWith("Test"));
if (pocoList != null)
{
foreach (var poco in pocoList)
{
Console.WriteLine(poco.Id + " : " + poco.Content);
}
}
}
}
}
And the repository/Unit of work and Context classes
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Data.Entity.Validation;
using System.Linq.Expressions;
namespace repofT
{
/// <summary>
/// Note to the reader. NO error handling. You should add your preferred solution.
/// This is a stripped down sample to illustrate how Repository of T pattern works.
/// </summary>
public class MyContext : DbContext
{
public DbSet<MyPoco> MyPocos { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//fluent API....
base.OnModelCreating(modelBuilder);
var entity = modelBuilder.Entity<MyPoco>();
entity.HasKey(t => t.Id) ;
entity.Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
public class MyPoco
{
//virtuals for EF, especially Proxies and navigation, Use public get/set
public virtual int Id { get; set; }
public virtual string Content { get; set; }
}
public class Repository<TPoco> where TPoco : class, new()
{
public DbContext Context { get; private set; }
public Repository(DbContext context){
Context = context;
}
public IList<TPoco> GetList(Expression<Func<TPoco, bool>> predicate)
{
// Investigate returning IQueryable versus IList as you learn more.
return GetQuery(predicate).ToList();
}
public IQueryable<TPoco> GetQuery(Expression<Func<TPoco, bool>> predicate)
{
// Investigate returning IQueryable versus IList as you learn more.
return Context.Set<TPoco>().Where(predicate);
}
public TPoco Get(Expression<Func<TPoco, bool>> predicate)
{
return Context.Set<TPoco>().FirstOrDefault(predicate);
}
public TPoco Find(params object[] keyValues)
{
return Context.Set<TPoco>().Find(keyValues);
}
public TPoco Attach(TPoco poco)
{
return Context.Set<TPoco>().Add(poco);
}
public TPoco Add(TPoco poco){
return Context.Set<TPoco>().Add(poco);
}
public TPoco AddOrUpdate(TPoco poco){
return Context.Set<TPoco>().Add(poco);
}
public TPoco Remote(TPoco poco){
return Context.Set<TPoco>().Remove(poco);
}
public void Change(TPoco poco){
Context.ChangeTracker.DetectChanges();
}
public void SetEntityState(TPoco poco, EntityState state = EntityState.Modified){
Context.Entry(poco).State = state;
}
}
public class UnitOfWork
{
public DbContext Context { get; protected set; }
public UnitOfWork(DbContext context){
Context = context;
}
public IEnumerable<DbEntityValidationResult> GetDbValidationErrors() { return
Context.GetValidationErrors();
}
public int Commit()
{
try {
var recs = Context.SaveChanges();
return recs;
}
catch (DbEntityValidationException efException){
var errors = GetDbValidationErrors(); // DO SOMETHING HERE !!!!!
return -1;
}
}
}
}