build a better data access layer - c#

In order to acces my db and use my stored procedures I made this very simple data access layer (if someone can call this "layer"). I have 8 files where each file looks like:
using System;
using System.Data;
using System.Data.Common;
using Microsoft.Practices.EnterpriseLibrary.Data;
public class TasksDBHandler
{
private static Database db = DatabaseFactory.CreateDatabase("DBNAME");
public static void SetTaskDepreciationData(long taskId, long fieldId, string value)
{
DbCommand command = db.GetStoredProcCommand("dbo.P_CUS_TSK_SetTaskDepreciationData");
db.AddInParameter(command, "#task_id", DbType.Int64, taskId);
db.AddInParameter(command, "#field_id", DbType.Int64, field);
db.AddInParameter(command, "#value", DbType.String, value);
db.ExecuteNonQuery(command);
}
//Many more stored procedures calls
}
I want to build a new and better data access layer but I don't know how should it look like. I want the ability to use stored procedures without the need to write static method for each stored procedure, I want better connection menagement and so on/
Is anyone have any clue how to do so?
I am using .Net and SQL SERVER.

Have you looked at any of the ORM products out there? There's Linq2Sql, Entity Framework, NHibernate, and others. Unless what you need to do is very basic, you'll probably have better results learning to use an existing framework than trying to write your own.
In an ORM like Entity Framework, you typically don't manage your connection manually, it defines an object (or entity) model from your database and a "context" which is responsible for retrieving the data from your database and mapping it to the correct properties on the classes in your entity model. So you request something from the context, it loads the data necessary to fulfill your request into memory, you work with it like other classes, and then tell the context to save your changes back to the database. There are several ways to interact with your entity model in entity framework, but the example I'll use is Linq2Entities. You write a Linq query, and the context is responsible for turning that into a query against the database *disclaimer: I haven't tried to run this code, it's just meant to serve as an example
using(MyEntitiesContext context = new MyEntitiesContext())
{
var idleUsers = from u in context.User
where u.LoggedIn && u.LastActivity > DateTime.Now.AddMinutes(-30)
select u;
foreach(User u in idleUsers)
{
u.Status = UserStatus.Idle;
}
context.SaveChanges();
}
Obviously there's a lot going on behind the scenes:
There's the whole object model that gets generated from your database (you select the tables you want to be included in your model, and you can create multiple models in the same project).
There's the context, which manages the database connection and turns your Linq expression into a database query
There's the connection string that has to be defined your .config file so Entity Framework knows how to connect to your database
You should be able to find plenty of information on Entity Framework, but the easiest way I've found to learn is to jump in and start trying to do something, and then find answers to questions as they come up. I wouldn't try to use it right away on something highly critical or time sensitive, as there's definitely a learning curve, and you'll learn better ways of working with it once you've experienced some of the pitfalls.
Here's a link to Microsoft's Entity Framework 4 Quickstart which should give you something fairly straightforward to try out. Have fun!

Related

Entity Framework C# queries from string parameters

I'm creating a web app based on a database. The datas in the database need to be displayed, edited and deleted by the web app user.
Right now I need to remove elements in my sqlite database table after the user inputs the name of the database table and the id (which is also the primary key) of the element. How can I do it?
I always used Entity Framework before and also in the Web App so I was looking for a solution with it, but if there's a simpler way to do it, I'll stick with it.
Thank you
I think the answer here is similar but I need help to adapt it to what I need now.
Entity Framework C# queries from strings
this is the UI
and here is the endpoint in the backend
//DELETE method
[HttpDelete("DeleteElementInTable")]
public IActionResult DeleteElementInTable(string tableName, string elementKey) //url query parameters
{
var db = new MyContext();
//code to remove the item ... something like:
DbManager.RemoveElement(tableName, elementKey); //DbManager is the static class dealing with the db context
return //csv of the deleted element;
}
I'm still a young developer but here I can see there are some lacks of knowledge. First of all, which technology are you using to build your web-app? From what you posted my guess is you are trying to use MVC. As #Panagiotis Kanavos said above you need an entity to interact with the database if you want to use Entity Framework, through which you don't need to pass table name in your GET function. Last but not less important you can't execute the delete operation in a GET function.

EF Core and Multiple Databases

I have a legacy system with three databases
Vendor
CustomCode
LogData
Vendor contains control and log data from our Vendors app.
CustomCode contains lots of views and stored procedures that joins to Vendor and LogData
LogData contains results from our CustomCode processes. eg: Daily/Weekly/Monthly summaries and results.
I'm writing a website that will plot data on a map. The list of units is from a view in CustomCode. The Summary record is from LogData, and the individual log points are retrieved from Vendor by a stored proc in CustomCode.
I started with a DbContext for CustomCode, but can't seem to Navigate to properties in a 2nd DbContext to LogData
Can I link navigation properties between objects in different contexts?
Can I have once context with multiple databases connected ?
Please note, this is nothing to do with multi-tenant or multi-schema
Can I link navigation properties between objects in different contexts?
No.
Can I have one context with multiple databases connected?
No.
Suggestion:
If the databases can communicate to each other (ie on same server), which appears to be already done since
CustomCode contains lots of views and stored procedures that joins to Vendor and LogData
then create a stored procedure to perform the desired queries (which can join tables from separate databases).
From there you should be able to expose and execute the procedure from Entity Framework to perform the desired functionality.
This would avoid have multiple contexts and trying to join the data in memory, which can have adverse effects if the data set is large.
Also answered elsewhere (https://stackoverflow.com/a/54347237/861352), but here's the gist:
This actually appears to be a known issue, with a solution in the pipeline (although it hasn't been prioritised yet):
https://github.com/aspnet/EntityFrameworkCore/issues/4019
I did however find an interim solution to this problem, and it's based on two sources:
https://stackoverflow.com/a/26922902/861352 (EF6 solution)
https://weblogs.asp.net/ricardoperes/interception-in-entity-framework-core
And here it is:
How To Do (Same Server) Cross DB Joins With One EF Core DbContext
You'll need to install the Microsoft.Extensions.DiagnosticAdapter Nuget Package
using System;
using System.Data.Common;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.Extensions.DiagnosticAdapter;
namespace Example
{
public class CommandInterceptor
{
[DiagnosticName("Microsoft.EntityFrameworkCore.Database.Command.CommandExecuting")]
public void OnCommandExecuting(DbCommand command, DbCommandMethod executeMethod, Guid commandId, Guid connectionId, bool async, DateTimeOffset startTime)
{
var secondaryDatabaseName = "MyOtherDatabase";
var schemaName = "dbo";
var tableName = "Users";
command.CommandText = command.CommandText.Replace($" [{tableName}]", $" [{schemaName}].[{tableName}]")
.Replace($" [{schemaName}].[{tableName}]", $" [{secondaryDatabaseName}].[{schemaName}].[{tableName}]");
}
}
}
Replace 'MyOtherDatabase', 'dbo' and 'Users' with your Database name, table schema and table name, maybe from a config etc.
Then attach that interceptor to your context.
using System.Diagnostics;
using Microsoft.EntityFrameworkCore.Infrastructure;
var context = new MultipleDatabasesExampleDbContext(optionsBuilder.Options);
// Add interceptor to switch between databases
var listener = context.GetService<DiagnosticSource>();
(listener as DiagnosticListener).SubscribeWithAdapter(new CommandInterceptor());
In my case I put the above in MultipleDatabasesExampleDbContextFactory method.
Now you can just use the context as if you were referencing one database.
context.Customers // Default database defined in connection string
context.Users // MyOtherDatabase (a different database on the same server)
In EF Core 5.0 new features, It is now easier to create a DbContext instance without any connection or connection string. Also, the connection or connection string can now be mutated on the context instance. This feature allows the same context instance to dynamically connect to different databases.
Reference: https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-5.0/whatsnew#use-a-c-attribute-to-indicate-that-an-entity-has-no-key
No, You cannot link navigation properties between objects in different contexts. A context represents a particular connection or DB. You can try getting data from multiple contexts (DBs) and join them and use in-memory.

Manipulating large quantities of data in ASP.NET MVC 5

I am currently working towards implementing a charting library with a database that contains a large amount of data. For the table I am using, the raw data is spread out across 148 columns of data, with over 1000 rows. As I have only created models for tables that contain a few columns, I am unsure how to go about implementing a model for this particular table. My usual method of creating a model and using the Entity Framework to connect it to a database doesn't seem practical, as implementing 148 properties for each column does not seem like an efficient method.
My questions are:
What would be a good method to implement this table into an MVC project so that there are read actions that allow one to pull the data from the table?
How would one structure a model so that one could read 148 columns of data from it without having to declare 148 properties?
Is the Entity Framework an efficient way of achieving this goal?
Entity Framework Database First sounds like the perfect solution for your problem.
Data first models mean how they sound; the data exists before the code does. Entity Framework will create the models as partial classes for you based on the table you direct it to.
Additionally, exceptions won't be thrown if the table changes (as long as nothing is accessing a field that doesn't exist), which can be extremely beneficial in a lot of cases. Migrations are not necessary. Instead, all you have to do is right click on the generated model and click "Update Model from Database" and it works like magic. The whole process can be significantly faster than Code First.
Here is another tutorial to help you.
yes with Database First you can create the entites so fast, also remember that is a good practice return onlye the fiedls that you really need, so, your entity has 148 columns, but your app needs only 10 fields, so convert the original entity to a model or viewmodel and use it!
One excelent tool that cal help you is AutoMapper
Regards,
Wow, that's a lot of columns!
Given your circumstances a few thoughts come to mind:
1: If your problem is the leg work of creating that many properties you could look at Entity Framework Power Tools. EF Tools is able to reverse engineer a database and create the necessary models/entity relation mappings for you, saving you a lot of the grunt work.
To save you pulling all of that data out in one go you can then use projections like so:
var result = DbContext.ChartingData.Select(x => new PartialDto {
Property1 = x.Column1,
Property50 = x.Column50,
Property109 = x.Column109
});
A tool like AutoMapper will allow you to do this with ease via simply configurable mapping profiles:
var result = DbContext.ChartingData.Project().To<PartialDto>().ToList();
2: If you have concerns with the performance of manipulating such large entities through Entity Framework then you could also look at using something like Dapper (which will happily work alongside Entity Framework).
This would save you the hassle of modelling the entities for the larger tables but allow you to easily query/update specific columns:
public class ModelledDataColumns
{
public string Property1 { get; set; }
public string Property50 { get; set; }
public string Property109 { get; set; }
}
const string sqlCommand = "SELECT Property1, Property50, Property109 FROM YourTable WHERE Id = #Id";
IEnumerable<ModelledDataColumns> collection = connection.Query<ModelledDataColumns>(sqlCommand", new { Id = 5 }).ToList();
Ultimately if you're keen to go the Entity Framework route then as far as I'm aware there's no way to pull that data from the database without having to create all of the properties one way or another.

Migrating Db and Entity framework

I have to take data from an existing database and move it into a new database that has a new design. So the new database has other columns and tables than the old one.
So basically I need to read tables from the old database and put that data into the new structure, some data won't be used anymore and other data will be placed in other columns or tables etc.
My plan was to just read the data from the old database with basic queries like
Select * from mytable
and use Entity Framework to map the new database structure. Then I can basically do similar to this:
while (result.Read())
{
context.Customer.Add(new Customer
{
Description = (string) result["CustomerDescription"],
Address = (string) result["CuAdress"],
//and go on like this for all properties
});
}
context.saveChanges();
I think it is more convenient to do it like this to avoid writing massive INSERT-statements and so on, but is there any problems in doing like this? Is this considered bad for some reason that I don't understand. Poor performance or any other pitfalls? If anyone has any input on this it would be appreciated, so I don't start with this and it turns out to be a big no-no for some reason.
Something that you could perhaps also try, is merely to write a new DBContext class for the new target database.
Then simply write a console application with a static method which copies entities and properties from the one context to the other.
This will ensure that your referential integrity remains intact and saves you a lot of hassle in terms of having to write SQL code, since EF does all the heavy lifting for you in this regard.
If the dbContext contains a lot of entity dbsets I recommend that you use some sort of automapper.
But, this depends on the amount of data that you are trying to move. If we are talking terrabytes, I would rather suggest you do not take this approach.

Entity Framework updating two databases

As I've mentioned in a couple other questions, I'm currently trying to replace a home-grown ORM with the Entity Framework, now that our database can support it.
Currently, we have certain objects set up such that they are mapped to a table in our internal database and a table in the database that runs our website (which is not even in the same state, let alone on the same server). So, for example:
Part p = new Part(12345);
p.Name = "Renamed part";
p.Update();
will update both the internal and the web databases simultaneously to reflect that the part with ID 12345 is now named "Renamed part". This logic only needs to go one direction (internal -> web) for the time being. We access the web database through a LINQ-to-SQL DBML and its objects.
I think my question has two parts, although it's possible I'm not asking the right question in the first place.
Is there any kind of "OnUpdate()" event/method that I can use to trigger validation of "Should this be pushed to the web?" and then do the pushing? If there isn't anything by default, is there any other way I can insert logic between .SaveChanges() and when it hits the database?
Is there any way that I can specify for each object which DBML object it maps to, and for each EF auto-generated property which property on the L2S object to map to? The names often match up, but not always so I can't rely on that. Alternatively, can I modify the L2S objects in a generic way so that they can populate themselves from the EF object?
Sounds like a job for Sql Server replication.
You don't need to inter-connect the two together as it seems you're saying with question 2.
Just have the two separate databases with their own EF or L2S models and abstract them away using repositories with domain objects.
This is the solution I ended up going with. Note that the implementation of IAdvantageWebTable is inherited from the existing base class, so nothing special needed to be done for EF-based classes, once the T4 template was modified to inherit correctly.
public partial class EntityContext
{
public override int SaveChanges(System.Data.Objects.SaveOptions options)
{
var modified = this.ObjectStateManager.GetObjectStateEntries(EntityState.Modified | EntityState.Added); // Get the list of things to update
var result = base.SaveChanges(options); // Call the base SaveChanges, which clears that list.
using (var context = new WebDataContext()) // This is the second database context.
{
foreach (var obj in modified)
{
var table = obj.Entity as IAdvantageWebTable;
if (table != null)
{
table.UpdateWeb(context); // This is IAdvantageWebTable.UpdateWeb(), which calls all the existing logic I've had in place for years.
}
}
context.SubmitChanges();
}
return result;
}
}

Categories

Resources