Making an application Database Agnostic - c#

I have an existing C# application, which I intend to make Database Agnostic, in such a way that the Database Engine is abstracted from the Business Logic completely.
Here is my approach to make one -
public abstract class DbEngine // I can also make it an Interface
{
}
public class SQLDBEngine : DbEngine
{
public bool ExecuteSP(string SPName)
{
}
public void ExecuteInlineQuery(String SQLQuery)
{
}
}
public class MySQLDBEngine : DbEngine
{
public bool ExecuteSP(string SPName)
{
}
public void ExecuteInlineQuery(String SQLQuery)
{
}
}
I then have a Factory class, which takes care of Instantiating the appropriate DbEngine object -
public class ConnectionManager
{
string CurrentEngine;
public ConnectionManager()
{
// Read from configuration file to know which database to configure
// Config returns wither MS or MY
// MS = SQLDBEngine
// MY = MYSQLDBEngine
}
public DbEngine GetDBInstance()
{
switch(CurrentEngine)
{
case "MS":
return new SQLDBEngine();
case "MY":
return new MySQLDBEngine();
default:
return new SQLDBEngine();
}
}
}
The Business Logic will only interact with the ConnectionManager object, thus abstracting the Database completely from it .
The Client will interact with the following code-
ConnectionManager conn = new ConnectionManager();
DBEngine obj = conn.GetDBInstance();
obj.ExecuteInlineQuery("select * from tblItems");
The Problem here, is that if the we introduce MongoDBEngine as the new database engine, this will require once more class MongoDBEngine - but since it doesn't have a Stored Procedure like feature, so ExecuteSP doesn't make sense and hence the Business Logic call will fail.
Iam just trying to encapsulate the Database Engine from the Business Logic, so that when the database is changed, the Business Logic should not undergo any change.
Is there any design pattern or technique that I could follow ?

Rather than trying to expose the functionality of the database to the application, you should abstract away the method of access. Instead of providing an ability to execute a query, embed that query or stored procedure call or insert/update/delete command as part of your repository class.
public class MySQLCustomerRepository : ICustomerRepository
{
private readonly string _connectionString;
public MySQLCustomerRepository(string connectionString)
{
_connectionString = connectionString;
}
public List<CustomerOrder> GetCustomerOrdersByDate(int customerId, DateTime startDate, DateTime endDate)
{
//open a MySQL connection and execute query to retrieve customer orders
}
}
public class MongoCustomerRepository : ICustomerRepository
{
private readonly string _connectionString;
public MongoCustomerRepository(string connectionString)
{
_connectionString = connectionString;
}
public List<CustomerOrder> GetCustomerOrdersByDate(int customerId, DateTime startDate, DateTime endDate)
{
//connect to mongo, get customers by running query
}
}
public interface ICustomerRepository
{
List<CustomerOrder> GetCustomerOrdersByDate(int customerId, DateTime startDate, DateTime endDate);
}
The consuming application itself should have no knowledge of queries, because the repository itself takes care of those details.
Part of the point of this is that each database will have different queries and commands that make sense for it. An SQL query written for MS SQL may not be the same as one written for Oracle, and of course SQL won't work at all on a no-SQL database. So each implementation should be responsible for using the correct interactions for its corresponding database, and your consuming application shouldn't need to know how that works, because it should always access the database via an interface, never through a concrete implementation .

I think the last answer from mason is a really step forward through a good desing. I would go one step further in OO desing and try to think as an object page for a Dto and return a sequence of something. A change i would do is to encapsulate the parameters of the methods inside the object and inject them through constructor, so this way you will have multiple clases implementing an abstraction of your query(1 class for a paged sequence, other class for searching for id, start and end time, etc. The result will be the same return type) instead of a big monster with a bunch of methods returning the same type. This way you get better mantainability, so if you have a issue with a mongo class for a specific query, you check one tiny class and not a GOD class, here is some paging desing:
/// <summary>
/// DTO
/// </summary>
public class CustomerOrder
{
public int Id { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}
/// <summary>
/// Define a contract that get a sequence of something
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IFetch<T>
{
IEnumerable<T> Fetch();
}
/// <summary>
/// Define a pageTemplate
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class PageTemplate<T> : IFetch<T>
{
protected readonly int pageSize;
protected readonly int page;
public PageTemplate(int page, int pageSize)
{
this.page = page;
this.pageSize = pageSize;
}
public abstract IEnumerable<T> Fetch();
}
/// <summary>
/// Design a MyDto Page object, Here you are using the Template method
/// </summary>
public abstract class MyDtoPageTemplate : PageTemplate<CustomerOrder>
{
public MyDtoPageTemplate(int page, int pageSize) : base(page, pageSize) { }
}
/// <summary>
/// You can use ado.net for full performance or create a derivated class of MyDtoPageTemplate to use Dapper
/// </summary>
public sealed class SqlPage : MyDtoPageTemplate
{
private readonly string _connectionString;
public SqlPage(int page, int pageSize, string connectionString) : base(page, pageSize)
{
_connectionString = connectionString;
}
public override IEnumerable<CustomerOrder> Fetch()
{
using (var connection = new SqlConnection(_connectionString))
{
//This can be injected from contructor or encapsulated here, use a Stored procedure, is fine
string commandText = "Select Something";
using (var command = new SqlCommand(commandText, connection))
{
connection.Open();
using (var reader = command.ExecuteReader())
{
if (reader.HasRows) yield break;
while (reader.Read())
{
yield return new CustomerOrder()
{
Id = reader.GetInt32(0),
Name = reader.GetString(1),
Value = reader.GetString(2)
};
}
}
}
}
}
}
public sealed class MongoDbPage : MyDtoPageTemplate
{
private readonly string _connectionString;
public MongoDbPage(int page, int pageSize, string connectionString) : base(page, pageSize)
{
_connectionString = connectionString;
}
public override IEnumerable<CustomerOrder> Fetch()
{
//Return From CustomerOrder from mongoDb
throw new NotImplementedException();
}
}
/// <summary>
/// You can test and mock the fetcher
/// </summary>
public sealed class TestPage : IFetch<CustomerOrder>
{
public IEnumerable<CustomerOrder> Fetch()
{
yield return new CustomerOrder() { Id = 0, Name = string.Empty, Value = string.Empty };
yield return new CustomerOrder() { Id = 1, Name = string.Empty, Value = string.Empty };
}
}
public class AppCode
{
private readonly IFetch<CustomerOrder> fetcher;
/// <summary>
/// From IoC, inject a fetcher object
/// </summary>
/// <param name="fetcher"></param>
public AppCode(IFetch<CustomerOrder> fetcher)
{
this.fetcher = fetcher;
}
public IEnumerable<CustomerOrder> FetchDtos()
{
return fetcher.Fetch();
}
}
public class CustomController
{
private readonly string connectionString;
public void RunSql()
{
var fetcher = new SqlPage(1, 10, connectionString);
var appCode = new AppCode(fetcher);
var dtos = appCode.FetchDtos();
}
public void RunTest()
{
var fetcher = new TestPage();
var appCode = new AppCode(fetcher);
var dtos = appCode.FetchDtos();
}
}

Related

When I saving an object, NHibernate tries to save object in database with id=0

I have NHibernate --version 2.1.2.4000 and use NHibernate.Mapping.Attributes
When i want to save object, like that
session.SaveOrUpdate(car);
session.Flush();
I have an exception "Cannot insert explicit value for identity column in table 'Car' when IDENTITY_INSERT is set to OFF." This happens when NHibernate tries set sql script with ID=0, like that
"exec sp_executesql N'INSERT INTO Car (...., Id) VALUES (.., #p12)',N'...,#p12 int', #p12=0 go"
My class has the following attribute
public class Car: ILifecycle {
[Generator(Class = "identity")]
[Id(0, Name = "Id", Column = "Id")]
public virtual int Id { get; set; }
public virtual LifecycleVeto OnDelete(ISession s);
public virtual void OnLoad(ISession s, object id);
public virtual LifecycleVeto OnSave(ISession s);
public virtual LifecycleVeto OnUpdate(ISession s);
}
Nhibernate helper has the following setting
public class NhibernateHelper {
private readonly string _configurePath;
/// <param name="path"></param>
public NhibernateHelper(string path) {
_configurePath = path;
}
/// <summary>The session factory.</summary>
private static ISessionFactory SessionFactory;
/// <summary>Gets current session.</summary>
/// <returns>The current session.</returns>
public static ISession GetCurrentSession() {
return SessionFactory.OpenSession();
}
/// <summary>Connects to database 1.</summary>
public void ConnectToDb() {
var configuration = new Configuration();
configuration.Configure(_configurePath);
HbmSerializer.Default.Validate = true;
Stream s = HbmSerializer.Default.Serialize(Assembly.GetExecutingAssembly());
configuration.AddInputStream(s);
var assembly = Assembly.Load("DAL");
s = HbmSerializer.Default.Serialize(assembly);
configuration.AddInputStream(s);
SessionFactory = configuration.BuildSessionFactory();
}
public void CloseSessionFactory() {
if (SessionFactory != null)
SessionFactory.Close();
}
}
I forgot about the numbers before the attributes.[Generator(1, Class = "identity")]

How to correctly abstract data access layer (for database, rest api calls, json) in C#?

I've been developing an application that uses various data connections (like database, rest api calls, json config files) in C#. I'm currently struggling to create a sensible data access layer abstraction that would enable to switch between these easily. Each of these require a different connection settings and also work differently.
I've looked at the example of the Repository pattern, but this doesn't really suit my needs. I want to be able to define some query pattern, which I can parametrize and that query will be able to handle the parameters. Example of what I currently have:
public interface IQuery<TResult>
{
}
public interface IQueryHandler<TQuery, TResult>
where TQuery : IQuery<TResult>
{
TResult Handle(TQuery query);
}
public class DatabaseQuery<TResult> : IQuery<IEnumerable<TResult>>
{
public string ConnectionString { get; set; }
public string CommandText { get; set; }
}
public class DatabaseConnection<TQuery, TResult> : IQueryHandler<TQuery, IEnumerable<TResult>>
where TQuery : DatabaseQuery<TResult>
{
public IEnumerable<TResult> Handle(TQuery query)
{
var results = new List<TResult>();
using (var connection = new SqlConnection(query.ConnectionString))
using (var command = new SqlCommand(query.CommandText, connection))
{
connection.Open();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
results.Add(...
}
}
}
return results;
}
}
public class JsonQuery<TResult> : IQuery<IEnumerable<TResult>>
{
public string FileLocation { get; set; }
public Func<TResult, bool> Condition { get; set; }
}
public class JsonConnection<TQuery, TResult> : IQueryHandler<TQuery, IEnumerable<TResult>>
where TQuery : JsonQuery<TResult>
{
public IEnumerable<TResult> Handle(TQuery query)
{
var text = File.ReadAllText(query.FileLocation);
return Deserialize<TResult>(text).Results.Where(query.Condition);
}
}
public interface IQueryBuilder<TQuery, TParameters>
{
TQuery Build(TParameters parameters);
}
public class GetAccountsByStatusAndBalanceHigherThanQueryParameters
{
public string Status { get; set; }
public decimal Balance { get; set; }
}
public class GetAccountsByStatusAndBalanceHigherThan_DatabaseQueryBuilder :
IQueryBuilder<DatabaseQuery<Account>, GetAccountsByStatusAndBalanceHigherThanQueryParameters>
{
public DatabaseQuery<Account> Build(GetAccountsByStatusAndBalanceHigherThanQueryParameters parameters)
{
return new DatabaseQuery<Account>()
{
ConnectionString = "connString",
CommandText = $"SELECT * FROM Accounts WHERE Status = {parameters.Status} AND Balance = {parameters.Balance}"
};
}
}
public class GetAccountsByStatusAndBalanceHigherThan_JsonQueryBuilder
: IQueryBuilder<JsonQuery<Account>, GetAccountsByStatusAndBalanceHigherThanQueryParameters>
{
public JsonQuery<Account> Build(GetAccountsByStatusAndBalanceHigherThanQueryParameters parameters)
{
return new JsonQuery<Account>()
{
FileLocation = "fileLocation",
Condition = acc => acc.Status == parameters.Status && acc.Balance > parameters.Balance
};
}
}
public class GetAccountsByStatusAndBalanceHigherThanQuery : IQuery<IEnumerable<Account>>
{
public string Status { get; set; }
public decimal Balance { get; set; }
}
public class GetAccountsByStatusAndBalanceHigherThanQueryHandler :
IQueryHandler<GetAccountsByStatusAndBalanceHigherThanQuery, IEnumerable<Account>>
{
private readonly IQueryBuilder<JsonQuery<Account>, GetAccountsByStatusAndBalanceHigherThanQueryParameters>
_queryBuilder;
private readonly IQueryHandler<JsonQuery<Account>, IEnumerable<Account>> _connection;
public GetAccountsByStatusAndBalanceHigherThanQueryHandler(
IQueryBuilder<JsonQuery<Account>, GetAccountsByStatusAndBalanceHigherThanQueryParameters> queryBuilder,
IQueryHandler<JsonQuery<Account>, IEnumerable<Account>> connection)
{
_queryBuilder = queryBuilder;
_connection = connection;
}
public IEnumerable<Account> Handle(GetAccountsByStatusAndBalanceHigherThanQuery query)
{
var jsonQuery = _queryBuilder.Build(new GetAccountsByStatusAndBalanceHigherThanQueryParameters
{
Status = query.Status,
Balance = query.Balance
});
return _connection.Handle(jsonQuery);
}
}
So there are two connections - one database and one Json file connection. I have put the settings to the connections into queries - and while database connection requires connection string and SQL command, the Json connection requires file location and some filtering on the results. The problem is in the last query handler - GetAccountsByStatusAndBalanceHigherThanQueryHandler. I need to make that depend on specific connection, otherwise I can't get it to compile. What I want is to make sure that I can change the connection by just changing the injected parameters and all will work correctly.
Could you please advise on how to make sure that I can change the connections easily and also whether this architecture is good at all?
I think you may be overcomplicating this. It looks to me like you have two data sources to retrieve the same data - one is a json data source and a database. This fits pretty neatly into the land of "one interface, multiple implementations". You'll also need a class to sort out which implementation you should use (this is a perfect use case for a factory). The complicated querying logic you're trying to pass into the constructors you could pass as method arguments.
Code would look something like this:
public interface IAccountDataAccess
{
IEnumerable<Account> GetAccountsHigherThanBalance(Status status, Balance balance);
// etc.
}
public class JsonAccountDataAccess : IAccountDataAccess
{
private string jsonFilePath;
public JsonAccountDataAccess(string _jsonFilePath)
{
jsonFilePath = _jsonFilePath;
}
public IEnumerable<Account> GetAccountsHigherThanBalance(Status status, Balance balance)
{
// read json file, extract data, etc.
}
}
public class DatabaseAccountDataAccess : IAccountDataAccess
{
private string connectionString;
public DatabaseAccountDataAccess(string _connectionString)
{
connectionString = _connectionString;
}
public IEnumerable<Account> GetAccountsHigherThanBalance(Status status, Balance balance)
{
// read database, extract data, etc.
}
}
Here's the tricky part - you need a factory to spit out the correct implementation given some input. I'm not sure how you're planning to decide whether to use JSON or the database, but assuming that your client class knows:
public class AccountDataAccessFactory
{
public IAccountDataAccess GetDataAccess(bool useDatabase)
{
if(useDatabase) // you could use arbitrarily complex logic here
return new DatabaseAccountDataAccess(connString);
else
return new JsonAccountDataAccess(jsonFilePath);
}
}
Your client class could use it like this:
var factory = new AccountDataAccessFactory();
var dataAccess = factory.GetDataAccess(true);
var accounts = dataAccess.GetAccountsHigherThanBalance(status, balance);

Castle Windsor resolve ienumerable and name

I'm new to Castle Windsor (actually to DI) and trying to solve a scenario using windsor and i'm kind of stuck. To give an idea, there are 2 different remote sources from where I need to get some order info for a given customer no on the first attempt which is bit time consuming. The order info will never change in the future hence i would like to store that data in my local database for any subsequent use(s) which will increase the performance of my application.
It seems like the decorator pattern is a good candidate for this and below is my initial attempt.
public interface IOrderRepository
{
IEnumerable<OrderInfo> Get(string customerNo);
void Save(string customerNo, IEnumerable<OrderInfo> orders);
}
public class RealTimeRepo1 : IOrderRepository
{
public IEnumerable<OrderInfo> Get(string customerNo)
{
/// Fetch the data from remote source 1
}
public void Save(string customerNo, IEnumerable<OrderInfo> orders)
{
/// You cannot update the order info in remote source
throw new NotImplementedException();
}
}
public class RealTimeRepo2 : IOrderRepository
{
public IEnumerable<OrderInfo> Get(string customerNo)
{
/// Fetch the data from remote source 2
}
public void Save(string customerNo, IEnumerable<OrderInfo> orders)
{
/// You cannot update the order info in remote source
throw new NotImplementedException();
}
}
public LocalOrderRepo : IOrderRepository
{
public IEnumerable<OrderInfo> Get(string customerNo)
{
/// Fetch the data from local data source
}
public void Save(string customerNo, IEnumerable<OrderInfo> orders)
{
/// Save the data on local data source
}
}
public CacheOrderRepo : IOrderRepository
{
private readonly IEnumerable<IOrderRepository> realTimeRepos;
private readonly IOrderRepository localRepo;
public CacheOrderRepo(IEnumerable<IOrderRepository> realTime, IOrderRepository localRepo)
{
this.realTimeRepos = realTime;
this.localRepo = localRepo;
}
public IEnumerable<OrderInfo> Get(string customerNo)
{
List<OrderInfo> orders = this.localRepo.Get(customerNo);
if(orders == null) && (!orders.Any()
{
foreach(var r in this.realTimeRepos)
{
List<OrderInfo> t = r.Get(customerNo);
if(t.Any())
{
orders.AddRange(t);
}
}
if(orders.Any())
{
this.localRepo.save(customerNo, orders);
}
}
return orders;
}
public void Save(string customerNo, IEnumerable<OrderInfo> orders)
{
/// Save the data on local data source
}
}
I hope the above code snippet gives an idea. My struggle is how to register this using windsor.
//regsiter
this._container.Kernal.Resolver.AddSubResolver(new
CollectionResolver(this._container.Kenrnal));
this._container.Register(
Component.For<IOrderRepository>.ImplementedBy<RealTimeRepo1>().LifeStyle.Transient,
Component.For<IOrderRepository>.ImplementedBy<RealTimeRepo2>().LifeStyle.Transient
);
Using the collection subresolver i was able to register an ienumerable of RealTime repos 1 & 2. How i should register the local repo (i.e. my constructor parameter 2)?
Appreciate your help. I'm also open for suggestions with my understanding of the decorator pattern or castle windsor...
Firstly you will need to register the CollectionResolver.
Secondly I suggest you either change the constructor of CacheOrderRepo to explicitly reference LocalOrderRepo or define a different abstraction (e.g. ILocalOrderRepo) for it.
public class CacheOrderRepo : IOrderRepository
{
private readonly IEnumerable<IOrderRepository> realTimeRepos;
private readonly LocalOrderRepo localRepo;
public CacheOrderRepo(IEnumerable<IOrderRepository> realTime, LocalOrderRepo localRepo)
{
this.realTimeRepos = realTime;
this.localRepo = localRepo;
}
The registration is then done by registering the composite (CacheOrderRepo) first, like this:
var container = new WindsorContainer();
container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel));
container.Register(
Component.For<IOrderRepository>().ImplementedBy<CacheOrderRepo>(),
Component.For<IOrderRepository>().ImplementedBy<RealTimeRepo1>(),
Component.For<IOrderRepository>().ImplementedBy<RealTimeRepo2>(),
Component.For<LocalOrderRepo>().ImplementedBy<LocalOrderRepo>());
var service = container.Resolve<IOrderRepository>();
Assert.IsInstanceOf<CacheOrderRepo>(service);

the balance between performance and code resue

i am currently working on a project, as the project builds up into lots of lines of code, so i am trying to take the trivial approach and start using some smarter way to make the code be reusable.
so for instance i need to connect to the Sql Server:
(it could be any other task i am learning while i code i am aware of all availble .Net built-in dedicated classes)
really all i need is :
SqlCommand, SqlDataReader (&SqlConnection) and the appropriate container object to return data
usually i am using List<dictionary<string, object>> for my tests with database
so till now it is very minimal i should think.
but, then i say ah that's a good way to connect to sql and fetch some rowsets
then i decide that this is not enough, cause there's some other kinds of returned data, so let's just make some alternative to cover more options, actually let's cover all available scenarios, and then i come up with a class full of "models" covering all available data Formats, single record multiple rows datasets, etc' .
but that's not all there's also 2 main options to read from sql server from .NET
like SqlDataReader And SqlDataAdapter. so i will cover those options too, but wait , there's also the magic words i could use such as stored procedurs and plain text command , so lets make a class that will hold some stractures to define a stored procedure, and then there's storedprocedure parameters, lets make an easy way to call a stored procedure as an object, so later one-line-call and we have a stored procedure object...
now if i will stop right here cause this is yet only the beginning there's much more in that rabbit hole.. and that even was not the best example as the objects created has a very good reason to exist, well unless you want to code it more efficiently you will not create those extra classes and objects
with this behavior and some more tasks to cover on a "daily basis" i begin to see there's a pattern that leads to a huge .Cs file that contains around 10 namespaces with Dozens of classes and functions on each.
the question is how do you decide when to use minimal code and when do you let it go and do not care a lot cause hey, the work station is on say .. 8 cores I7 machine there would not be much of a difference, so lets just worry about the ease of coding.
where do you put the red line ?
Edit the code below is not for a code review purpose, it's just to show the scale of the application and the performance impact it could lead to.**
this is only the core of the data object factory, thats about 1/3 of the class which one of a few in other realted tasks.
public class Inventory
{
public class DataCariers
{
public class DbDataCar
{
public Prototypes.DataCarPrototypes.CarTypeMeta CarierSpec { get; set; }
public AlsDataCariers.Inventory.Compartments.DataCarCompartment Trunk { get; set; }
public string CarierName { get; private set; }
public DbDataCar(AlsTransMods.Direction bsDir, AlsTransMods.CarSize bsCs, AlsTransMods.useCar bsFamType, Compartments.DataCarCompartment bsTrunk)
{
this.CarierSpec = new Prototypes.DataCarPrototypes.CarTypeMeta()
{
CarDirection = bsDir,
carOfSize = bsCs,
CarFamilySelected = bsFamType
};
this.Trunk = bsTrunk;
this.Trunk.Value = new object();
this.Trunk.compTypeMeta.CompartmentParent = this.GetType();
}
public DbDataCar(Prototypes.DataCarPrototypes.CarTypeMeta bsCarierSpec, Compartments.DataCarCompartment bsTrunk)
{
this.CarierSpec = bsCarierSpec;
this.Trunk = bsTrunk;
this.Trunk.Value = new object();
this.Trunk.compTypeMeta.CompartmentParent = this.GetType();
}
internal void SetTunk(string CsvVal)
{
//this.Trunk = new AlsDataCariers.Inventory.Compartments.GenericsDataCarCompartment.Singles(CsvVal);
if (this.CarierSpec.CarDirection == AlsTransMods.Direction.In)
{
// new Compartments.MultipleRowsTabedMultipleRecordsCompartmnet(new prototypesFactory.DataCarPrototypes.selectionsTypeCreator(prototypesFactory.DataCarPrototypes.SelectionMode.selectionMultyRow).SelectedSelectionType);
}
else this.Trunk.Value = new Csv() { val = CsvVal };
}
}
public class GenericDbDataCar : DbDataCar
{
public GenericDbDataCar(AlsTransMods.Direction bsDir, AlsTransMods.CarSize bsCs, AlsTransMods.useCar bsFamType, Compartments.DataCarCompartment bsTrunk)
: base(bsDir, bsCs, bsFamType, bsTrunk)
{
this.CarierSpec = new Prototypes.DataCarPrototypes.CarTypeMeta();
this.CarierSpec.CarDirection = bsDir;
this.CarierSpec.carOfSize = bsCs;
this.CarierSpec.CarFamilySelected = bsFamType;
this.CarierSpec.CarOfType = this.GetType();
base.CarierSpec = this.CarierSpec;
//this.Trunk = this.TrunkCreate();
//base.Trunk = this.Trunk;
}
public GenericDbDataCar(Prototypes.DataCarPrototypes.CarTypeMeta bsCarierSpec, Compartments.DataCarCompartment bsTrunk)
: base(bsCarierSpec, bsTrunk)
{
this.CarierSpec.CarOfType = this.GetType();
base.CarierSpec = this.CarierSpec;
}
}
public class TabularDbDataCar : DbDataCar
{
public TabularDbDataCar(AlsTransMods.Direction bsDir, AlsTransMods.CarSize bsCs, AlsTransMods.useCar bsFamType, Compartments.DataCarCompartment bsTrunk)
: base(bsDir, bsCs, bsFamType, bsTrunk)
{
this.CarierSpec = new Prototypes.DataCarPrototypes.CarTypeMeta();
//this.CarierName = string.Concat(bsCs, bsFamType);
this.CarierSpec.CarDirection = bsDir;
this.CarierSpec.carOfSize = bsCs;
this.CarierSpec.CarFamilySelected = bsFamType;
this.CarierSpec.CarOfType = this.GetType();
base.CarierSpec = this.CarierSpec;
}
public TabularDbDataCar(Prototypes.DataCarPrototypes.CarTypeMeta bsCarierSpec, Compartments.DataCarCompartment bsTrunk):base(bsCarierSpec, bsTrunk)
{
this.CarierSpec.CarOfType = this.GetType();
}
}
}
public class Compartments
{
public class DataCarCompartment
{
//private Prototypes.DataCarPrototypes.selectionsType selectionsType;
public RobCs509b.MyModels.Prototypes.DataCarPrototypes.CompartmentMeta compTypeMeta{get; private set;}
public DataCarCompartment(RobCs509b.MyModels.Prototypes.DataCarPrototypes.CompartmentMeta Bs_CompTypeMeta)
{
this.compTypeMeta = Bs_CompTypeMeta;
this.compTypeMeta.CompartmentSeed = this.GetType();
}
public virtual object Value { get; set; }
}
public class TabularDataCarCompartment : DataCarCompartment
{
public TabularDataCarCompartment(Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
base.compTypeMeta.CompartmentFamilyType = this.GetType();
}
}
public class TabedSingleRecordComartment : TabularDataCarCompartment
{
public TabedSingleRecordComartment(Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
base.compTypeMeta.CompartmentDeliverBaseType = this.GetType();
this.Value = new DataColumn();
base.compTypeMeta.CompartmentDeliverType = this.Value.GetType();
}
public new DataColumn Value;
}
public class TabedMultipleRecordsCompartment : TabularDataCarCompartment
{
public TabedMultipleRecordsCompartment(Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
base.compTypeMeta.CompartmentDeliverBaseType= this.GetType();
}
}
public class TabedSingleRowMultipleRecordsCompartment : TabedMultipleRecordsCompartment
{
public TabedSingleRowMultipleRecordsCompartment(Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
base.compTypeMeta.CompartmentDeliverBaseType = this.GetType();
base.compTypeMeta.CompartmentDeliverType = this.Value.GetType();
base.Value = this.Value;
}
public new DataRow Value;
}
public class MultipleRowsTabedMultipleRecordsCompartmnet : TabedMultipleRecordsCompartment
{
public MultipleRowsTabedMultipleRecordsCompartmnet(Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
base.compTypeMeta.CompartmentDeliverBaseType = this.GetType();
this.Value = new DataTable();
base.compTypeMeta.CompartmentDeliverType = this.Value.GetType();
base.Value = this.Value;
}
public new DataTable Value;
}
public class MultipleRowsClonedTabedMultipleRecordsCompartmnet : TabedMultipleRecordsCompartment
{
public MultipleRowsClonedTabedMultipleRecordsCompartmnet(Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
base.compTypeMeta.CompartmentDeliverBaseType = this.GetType();
this.Value = new ClonedSchemaDtt("NotSet");
base.compTypeMeta.CompartmentDeliverType = this.Value.GetType();
}
public new ClonedSchemaDtt Value;
}
public class GenericDataCarCompartment : DataCarCompartment
{
public GenericDataCarCompartment(Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
base.compTypeMeta.CompartmentFamilyType = this.GetType();
}
}
public class GenericSingelRecordCompartment : GenericDataCarCompartment
{
public GenericSingelRecordCompartment(Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
}
}
public class GenericSingleCsv :GenericSingelRecordCompartment
{
public GenericSingleCsv(string CsvVal,Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
this.Value = new Csv();
this.Value.val = CsvVal;
}
public new Csv Value;
}
public class GenericMultipleRecordsCompartment : GenericDataCarCompartment
{
public GenericMultipleRecordsCompartment(Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
}
//public RepetablevaluesCollections RepeatbleCollNameVal;
//public UniqCollectionNameval UniqCollNameVal;
}
public class GenericSingleRowMultipleRecordsCompartment3s: GenericMultipleRecordsCompartment
{
public GenericSingleRowMultipleRecordsCompartment3s(Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
base.compTypeMeta.CompartmentDeliverBaseType = this.GetType();
this.Value = new MyGenericObject3<string, string, string>("", "", "");
base.compTypeMeta.CompartmentDeliverType = this.Value.GetType();
}
/// <summary>
/// MyGenericObject3 (string,string,string) values.
/// </summary>
public new MyGenericObject3<string, string, string> Value;
}
public class GenericMultipleRowsMyGenericObj3DataCarCompartment:GenericMultipleRecordsCompartment
{
public GenericMultipleRowsMyGenericObj3DataCarCompartment (Prototypes.DataCarPrototypes.CompartmentMeta compartmentMeta)
: base(compartmentMeta)
{
base.compTypeMeta.CompartmentDeliverBaseType = this.GetType();
this.Value = new List<MyGenericObject3<string, string, string>>();
base.compTypeMeta.CompartmentDeliverType = this.Value.GetType();
base.Value = this.Value;
}
/// <summary>
/// DbMagaZine (List MyGenereicObject3) valueType
/// </summary>
public new List<MyGenericObject3<string, string, string>> Value;
}
}
public class CompartmentTypes
{
private CompartmentTypes creator;
public CompartmentTypes ()
{
}
}
}
public class Compartments
{
public class Tabular :Inventory.CompartmentTypes
{
Type CompartmentOfFamilyType = typeof(System.ComponentModel.MarshalByValueComponent);
Type CompartmnetOfType = typeof(Tabular);
}
public class Generic : Inventory.CompartmentTypes
{
Type CompartmnetOfType = typeof(Generic);
}
}
The problem of yours is, that there are so many options to do the same thing.
My advise is to use the technology that is easiest to program and only switch to lower level abstractions if absolutely necessary for perfomance reasons.
And don't compare performance for simple cases but think about the whole system performane and maintenance.
I did database programming in the pre Entity Framework times, and it takes much more expertise and effort to this correctly, so I would not recommend this as of today.
So I reccommend technology in the following order:
Entity Framework pure
Entity Framework with stored procedures for special cases
Datasets and hand crafted logic
Datasets with stored procedures for special cases
SqlDatareader for read only sequential access of a whole table

There is no argument given that corresponds to the required formal parameter - .NET Error

I have been refactoring one of my old MSSQL Connection helper library and I got the following error:
Error CS7036 There is no
argument given that corresponds to the required formal parameter
'errorMsg' of 'ErrorEventArg.ErrorEventArg(string,
string)' MSSQLTest C:\Users\Administrator\Desktop\MSSQLTest\MSSQLTest\MSSQLConnection.cs 61
This is my code so far:
MSSQLConnection.cs
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Threading;
namespace MSSQLTest
{
public class ErrorEventArg : EventArgs
{
public string ErrorMsg { get; set; }
public string LastQuery { get; set; }
public ErrorEventArg(string errorMsg, string lastQuery)
{
ErrorMsg = errorMsg;
LastQuery = lastQuery;
}
}
public class MSSQLConnection
{
/// <summary>
/// Private class objects.
/// </summary>
private SqlConnection sqlConnection;
private int sqlCommandTimeout;
private string lastQuery = string.Empty;
/// <summary>
/// Public event related objects & handler.
/// </summary>
public event ErrorHandler OnError;
public delegate void ErrorHandler(MSSQLConnection sender, ErrorEventArg e);
/// <summary>
/// Class constructor.
/// </summary>
/// <param name="sqlConnection"></param>
/// <param name="sqlCommandTimeout"></param>
public MSSQLConnection(SqlConnection sqlConnection, Int32 sqlCommandTimeout = 120)
{
if (null == sqlConnection)
throw new Exception("Invalid MSSQL Database Conection Handle");
if (sqlConnection.State != System.Data.ConnectionState.Open)
throw new Exception("MSSQL Database Connection Is Not Open");
this.sqlConnection = sqlConnection;
this.sqlCommandTimeout = sqlCommandTimeout;
}
/// <summary>
/// Helper method to emit a database error to event subscribers.
/// </summary>
/// <param name="errorMsg"></param>
internal void EmitError(String errorMsg)
{
var errorDelegate = OnError;
if (errorDelegate != null)
{
errorDelegate(this, new ErrorEventArg() // Line #61
{
ErrorMsg = errorMsg,
LastQuery = lastQuery
});
}
}
/// rest of the code snipped
}
}
What does this error means & how do I fix it? I've not seen this error before...
In the constructor of
public class ErrorEventArg : EventArgs
you have to add "base" as follows:
public ErrorEventArg(string errorMsg, string lastQuery) : base (string errorMsg, string lastQuery)
{
ErrorMsg = errorMsg;
LastQuery = lastQuery;
}
You have a constructor which takes 2 parameters. You should write something like:
new ErrorEventArg(errorMsv, lastQuery)
It's less code and easier to read.
EDIT
Or, in order for your way to work, you can try writing a default constructor for ErrorEventArg which would have no parameters, like this:
public ErrorEventArg() {}
I got the same error but it was due to me not creating a default constructor. If you haven't already tried that, create the default constructor like this:
public TestClass()
{
}
I got this error when one of my properties that was required for the constructor was not public. Make sure all the parameters in the constructor go to properties that are public if this is the case:
using statements
namespace someNamespace
public class ExampleClass {
//Properties - one is not visible to the class calling the constructor
public string Property1 { get; set; }
string Property2 { get; set; }
//Constructor
public ExampleClass(string property1, string property2)
{
this.Property1 = property1;
this.Property2 = property2; //this caused that error for me
}
}
I received this same error in the following Linq statement regarding DailyReport. The problem was that DailyReport had no default constructor. Apparently, it instantiates the object before populating the properties.
var sums = reports
.GroupBy(r => r.CountryRegion)
.Select(cr => new DailyReport
{
CountryRegion = cr.Key,
ProvinceState = "All",
RecordDate = cr.First().RecordDate,
Confirmed = cr.Sum(c => c.Confirmed),
Recovered = cr.Sum(c => c.Recovered),
Deaths = cr.Sum(c => c.Deaths)
});
public ErrorEventArg(string errorMsg, string lastQuery)
: base (errorMsg, lastQuery)
{
ErrorMsg = errorMsg;
LastQuery = lastQuery;
}
to call base constructor the parameters of sub class and base class must be same.

Categories

Resources