Dapper.Rainbow with existing database schema - c#

I am trying out Dapper. I like what I have seen so far. In order to do simple CRUD, I use Dapper.rainbow. It works very well. However, it works only if the table has identity column with name Id. It makes sense to have db like that but I can not ask for column name change in database just to use Dapper. To be more clear, I am working with database like Northwind Db. It has tablename repeated in Id column everywhere.
In order to handle this,I changed the Dapper.Rainbow code as below:
public T Get(TId id,string idColumnName="Id")
{
return database.Query<T>("select * from " + TableName + " where "+idColumnName+" = #id", new { id }).FirstOrDefault();
}
Is there a better way to handle this such as Column mapping /annotations or something completely different?
I have read questions like these
Manually Map column names with class properties
Dapper.Rainbow VS Dapper.Contrib
( I came across similar little problem with Dapper.Contrib, I will ask it separately).
Update - Not sure if the answers are applicable to my Dapper.Rainbow problem here (Atleast, I don't see how).
Thanks for help in advance!

I had a similar problem. The existing Dapper extensions did not fit my ideal pattern. I wanted simple CRUD operations with smart defaults without anything extra. I also wanted to have models with additional properties that did not directly map to the database. For example - a FullName property that combines FirstName and LastName in its getter - and not add FullName to the Insert and Update statements.
I wanted the primary key column to be Id in most cases but allow overriding with an attribute.
Finally, I wanted the table name to match the class name by default but allow overriding with an attribute.
I ended up writing my own extension to Dapper that solves these issues. Its on Github and Nuget. Hopefully it will be helpful to you.
https://github.com/ericdc1/Dapper.SimpleCRUD

Related

Redirect queries from one entity to another using c# / entity framework

This is a bit of a puzzle I'm trying to figure out.
I am working on a system where we have a number of company records saved in the database. Some of these records are duplicates and are no longer wanted/required.
However, several external systems are still mapping to these invalid records. If we were to delete them entirely it would cause errors to the systems still wanting to get the detail of that company.
The ideal workflow I would like would be;
The external system looks up Company ID X.
The current system has a table which has a record of all the remapped records, so when the request comes in, the table specifies to redirect Company ID X to Company ID Y.
There are a number of endpoints that could be altered one-by-one to do this - but it would be time-consuming, resulting in lots of repetition too.
My question is, using Entity Framework and .Net - is there a smart way of achieving this workflow?
My initial thoughts were to do something with the constructor for the company object, which repopulates the object from EF if a 'redirect' exists, but I don't know if this will play nice with navigation properties.
Would anyone have an idea?
Thanks very much.
You can create a column with foreign key for the same table to express the single unique valid company.
For example, you can add DuplicateOf column:
ALTER TABLE [Company]
ADD COLUMN [DuplicateOf] bigint NULL,
FOREIGN KEY [DuplicateOf] REFERENCES [Company] ([Id]);
and express this relation in your code:
public class Company
{
// ...
public Company DuplicateOf { get; set; }
// May be useful, hides check for duplicate logic:
public bool IsDuplicate => DuplicateOf != null;
// May be useful as well,
// returns the non-duplicate uniue company, not a duplicate, either linked or current:
public Company EffectiveCompany => DuplicateOf ?? this;
}
You will have to address EffectiveCompany when you want to work with non-duplicate and maintain this column to always point to the correct record. It will also result into additional query, if eager-loaded.
Another idea is to have a stored procedure GetCompany(bigint id) which will return the effective record - if DuplicateOf exists, or record itself otherwise. It will be good for your external systems and will let you hide all this stuff behind abstraction layer of stored procedure. If you decide to change it in future, then you can easily update it without breaking external systems.
However, for you it isn't always convenient to work with stored procedures with EF.
These are just ideas and not the best solutions, anyway.
In my opinion, the best solution would be to get rid of duplicates, update data everywhere and forget forever about this mess of duplicated data.

Entity Framework 6 is not mapping my columns correctly using Attributes

I am using EF6 to query data from a database. The database existed before the code and belongs to another application, so I cannot modify the database at all. I believe I am using a code first approach, even though the database already exists(Forgive me as I'm new to EF). The issue is that I am not able to pull back data for a column that is setup as follows;
[Column("ITEM_QTY")]
public decimal ItemQuantity { get; set; }
Now if I rename the property to ITEM_QTY, it pulls the data correctly. I'm not sure what I'm missing. I can pull data from any other field correctly, but this field returns 0 regardless of whats in the DB. Can anyone provide any direction?
In another discussion, someone had suggested a possible issue with the underscores in the column name. Not sure if that could be it, but adding for info. Thanks.
Edit: Adding code used to query database. Note that this was setup before I started working on the project, so following same convention;
var t = this.Database.SqlQuery<InventoryDb>("select top 100 * from COMPANY_INVENTORY with (NOLOCK) where COMPANY = #CompanyName",
new SqlParameter("CompanyName", companyName)).ToList();
Your Column attribute will be ignored if you are using custom SqlQuery<T> on the DbContext. You need to pass the Sql statement with the alias for the property name that matches your entity.
var t = this.Database.SqlQuery<InventoryDb>("select top 100 Item_QTY as [ItemQuantity], ... other columns ... from COMPANY_INVENTORY with (NOLOCK) where COMPANY = #CompanyName",
new SqlParameter("CompanyName", companyName)).ToList();
EDIT:
Was checking this further out of curiosity and it appears that EF should respect the Column attribute if you used the DbSet.SqlQuery instead. I have not tried this though. (https://msdn.microsoft.com/en-us/library/system.data.entity.dbset.sqlquery(v=vs.113).aspx)
var t = this.Inventory.SqlQuery("select top 100 * from COMPANY_INVENTORY with (NOLOCK) where COMPANY = #CompanyName",
new SqlParameter("CompanyName", companyName)).ToList();

Dapper insert syntax

I use orm dapper from c# application for mysql database access. It works fine. There's only syntax question. I have a class with a many properties. All this properties matches database table fields exactly. So Select request is pretty short:
var listOfInstances = con.Query<MyClass>("Select * From myTable");
but when I need to insert something into database I have to write all those properties names that looks a little bit ugly:
con.Execute(#"Insert into myTable values(#Id, #Property1, #Property2, #Property3, #Property4, ....)", listOfInstances);
I wonder if there are any shorter syntax to insert data, at least for such a case when all class properties matches database table fields exactly.
P.S. The same thing about Update request
P.P.S. If say honestly I just start to work with a database which contains many tables, so I had to write basic functions get/add/change instance for each of those tables and it is quite annoing to list all of their fields.
Basically you need to install a nuget package called Dapper.Contrib
here's the repo
https://github.com/StackExchange/dapper-dot-net/tree/master/Dapper.Contrib
Also check this out https://samsaffron.com/archive/2012/01/16/that-annoying-insert-problem-getting-data-into-the-db-using-dapper

How do I get SimpleMembershipProvider extended properties back from database like FirstName and LastName?

Following this post, SimpleMemberShipProvider, Using multiple PropertyValues with custom Database tables, I successfully create a new user using the SimpleMembershipProvider and WebMatrix.WebData.WebSecurity.
WebSecurity.CreateUserAndAccount(model.UserName, model.Password,new { FirstName = model.FirstName,LastName = model.LastName,AppId = Guid.NewGuid(), MemberId = model.MemberId});
However, I have not been able to find any built-in methods for retrieving this information back from MembershipProvider or WebSecurity methods. I know I could query the database directly to get the information back and update, but then my code would become tightly coupled with this test implementation.
Anyone know how to get extended properties from a currently logged in user in the SimpleMembershipProvider? Thanks.
SBirthare is right, however, since he doesn't explain how to do this, allow me (this is assuming you use the C# server-side language option, which you tagged, so I believe you do. This also assumes that the table name in which the "FirstName" and "LastName" columns belong is, in fact, "UserProfile"):
Since WebMatrix comes with SQL Server-CE, we can just use a simple SQL query for this.
First set up your connection to the database:
var db = Database.Open("Users");
Next, compile the appropriate string to be used for the query (a simple string variable is used):
string selectQueryString = "SELECT FirstName, LastName FROM UserProfile";
The above string when passed to the Query() C# method (shown below), will however return a list (specifically IEnumerable<dynamic>) of all "FirstName"s and "LastName"s returned from the database. If you only wanted certain rows returned you can use the WHERE clause in the SQL string, so instead of the above string you could make this instead (this is just an example, you will have to tailor your own conditions to fit your situation, but this should give you an easy example):
string selectQueryString = "SELECT FirstName, LastName FROM UserProfile WHERE Email = #0 AND UserID = #1";
First let me address what the #0 and the #1 is, in case you don't already know. They are placeholders that will end up being filled with the conditions you want to test against (more on this further down) using this method, known as "paramaterized queries", this will be your smoking gun against SQL injection attacks. In short: ALWAYS USE THIS METHOD FOR CONDITIONS TESTED IN THE WHERE CLAUSE (I really can't stress this enough).
Now, I'm not sure how much you know about SQL querying, but they can be very powerful and useful and by using things like LIKE, ORDER BY, GROUP BY, JOIN, UNION, AND, OR, or even subqueries, as well as, many many other keywords and approaches, you can really make the SQL query return just about anything you desire, in the order you desire (a great beginner SQL query tutorial can be found here: http://www.sqlcourse.com/index.html).
Okay, moving on... Once you've written the selectQueryString the way that you want to, all you need left is to store it, like so:
int ID = 6;
string email = "testEmailName#gmail.com";
var queryResultsList = db.Query(selectQueryString, email, ID); //Here the first argument passed to the `db.Query()` method is the query string, but each additional argument passed (and you can actually pass an array of values here instead if you want) is used to fill the `#0` and `#1` placeholders you formed in your string earlier (order is ever important here!).
And display it, like so:
foreach (var row in queryResultsList)
{
//Do something for each row returned, here!
<div>FIRST NAME: #row.FirstName</div><br/>
<div>LAST NAME: #row.LastName</div>
{
Sorry if this is a lot to take in, but I thought I would at least show you all of the steps that you need to actually make this happen. Really there isn't that much to it, I just felt like giving you a bunch of helpful pointers a long the way :)
Anyway, just let me know if you have any questions or if I need to clarify anything.
EDIT:
Well, I just saw that you use MVC as opposed to Web-Pages. My answer is from the Web-Pages environment, but to be honest, I'm not sure if it would be any different or not because I have never worked with MVC. Either way, the SQL query itself should be the same and since we're both using C#, idk.
Either way, if I am told that this answer doesn't fit the scenario or is not useful to you, I will be glad to delete it.
As far as I know you will have to query the table using your current ORM framework.
SimpleMembershipProvider and WebSecurity allows you basic stuff e.g. WebSecurity.CurrentUserName, WebSecurity.UserExists, WebSecurity.GetUserId, etc.
The custom column you add into any of the tables created by SimpleMembershipProvider have to be fetched manually from the table.
SimpleMembershipProvider have no idea that you added FirstName and LastName into UserProfile (or other table) table.

Retrieve just some columns using an ORM

I'm using Entity Framework and SQL Server 2008 with the Database First approach.
My problem is :
I have some tables that holds many many columns (~100), and when I try to retrieve a lot of rows it takes a significant time before it returns the results, even if sometimes I need to use just 3 or 4 columns from that table.
I passed half a day in Stackoverflow trying to find a way to solve this problem, and I came up with two solutions :
Using stored procedures to retrieve data with the columns I want.
Edit the .edmx (xml) and the .cs files to remove the columns that I won't use.
My problem again is :
If I use stored procedures to retrieve the data with the columns that I want, Entity Framework loose it benefit and I can use ADO.NET instead of it and call directly the stored procedures ...
I can't take the second solution, because every time I make a change in the database, I'm obliged to regenerate the .edmx file and I loose the changes I made before :'(
Is there a way to do this somehow in Entity Framework ? Is that possible !
I know that other ORMs exist like NHibernate or Dapper, but I don't know if they can offer this feature without causing a lot of pain.
You don't have to return every column each time. You can specify which columns you need.
var query = from t in db.Table
select new { t.Column1, t.Column2, t.Column3 };
Normally if you project the data into a different poco it will do this automatically in EF / L2S etc:
var slim = from row in db.Customers
select new CustomerViewModel {
Name = row.Name, Id = row.Id };
I would expect that to only read 2 columns.
For tools like dapper: since you control the SQL, only specify columns you want - don't use *
You can create a second project with a code-first DbContext, POCO's and maps that return the subset of columns that you require.
This is a case of cut and paste code but it will get you what you need.
You can just create classes and project the data into them but I'm not sure you can make updates using this method. You can use anonymous types within a single method but you'll need actual classes to pass around between methods.
Another option would be to move to a code first development.

Categories