So I have a simple key-value table BillTypes in my SQL Server. It looks like this:
+----+-------------+
| Id | Description |
+----+-------------+
| 1 | OK |
| 2 | Missing |
| 3 | Maximum |
| 4 | Minimum |
| 5 | Error |
+----+-------------+
The table holds different types of bill states. I have another table Items with a foreign key BillType, referring to Id in the previous table.
+----------+------+--------+
| IdItem | Cash |BillType|
+----------+------+--------+
| * | * | * |
| * | * | * |
| * | * | * |
| ... |... | ... |
+----------+------+--------+
Then, in my application I get data from the second table via a stored procedure. In this sp, I am not sure if should select the BillType as it is, a tinyint, or use an innerjoin to return the description instead. The thing is, my application has some logic depending on the BillType, i.e. rows will be processed differently depending on the BillType. Should my logic depend on the Id or the description??
In code, should I have something like this?
DataTable dt = ...//call stored procedure that selects the BillType id
foreach(Datarow r in dt)
{
if(r["BillType"] == 3) ... //use logic
}
or this?
DataTable dt = ...//call stored procedure that selects the BillType description
foreach(Datarow r in dt)
{
if(r["BillType"] == "Maximum") ... //use logic
}
I am currently using the second way, with descriptions, because I think it makes code more readable. I am however worried about the possibility that someone might change the descriptions and break my application logic. On the other hand, using ids would be less readable(though i could work around this with an enum) and would be invulnerable to description changes, but still if someone changed an id, things would break.
To be honest, we don't expec anyone to mess around with the first table, since we made it specially for this application. Still, I am new to SQL and I am trying to learn the best practices of application-SQL interaction, so I would like to know how experienced people do it
Please consider this a comment rather than an answer (I don't yet have enough rep to comment).
I prefer the latter (as you are doing), where I rely on the description.
If your IDs are SQL indentity fields (which auto-increment) Consider the following scenario:
You build your app and database in DEV environment
The production deployment gets back out and re-run
Now, rather than IDs 1,2,3 you have 4,5,6
Generally speaking, it makes more sense to rely on IDs instead of values. After all, IDs should be unique, whereas values can have duplicates/change. Although you are not expecting any changes to the BillTypes table, I wouldn't use the string values, as you suggested.
Since updates/deletes/inserts can still happen in the BillTypes table and you want to be prepared as well as have readable code, the easiest thing to do would be if you define your own enum as such:
public Enum BillTypesEnum
{
OK = 1,
Missing = 2,
Maximum = 3,
Minimum = 4,
Error = 5
};
If something happens and you need to add something to the database, you do it and then change the Enum. It would also work if you delete the "Error" entry and insert "Average". You would not get Average=5 but probably Average=6 or something higher. The enum structure lets you define the values with no problem.
Then you can use it all over your code, not just in this single instance. Your code is modified below:
DataTable dt = ...//call stored procedure that selects the BillType id
foreach(Datarow r in dt)
{
if(r["BillType"] == (int)BillTypesEnum.Maximum) ... //use logic
}
This makes the code more readable then before, you dont have to hard-code the values all over your code but just in one place. And if it happens,that you will not be changing the database, then it's just a plus.
Another option would be to do the spGetAllBillTypes (select * from tblBillTypes) and then internally create a dictionary.
Dictionary<string,int> dictBillTypes = new Dictionary<string,int>();
int = billTypeId
string = billTypeText
When you retrieve your data from the child table (the one with the foreign key), you retrieve your billtypetext.
You can then do it like this:
DataTable dt = ...//call stored procedure that selects the BillType id
foreach(Datarow r in dt)
{
if(r["BillType"] == dictBillTypes["Maximum"]) ... //use logic
}
...but this is still an incomplete solution, because here, you rely on two things:
1. that the billTypeText will not change (if it does, you have to change it in the code)
2. that the billTypeText will not have duplicates (otherwise you will get an exception about duplicate key value in the dictionary)
Another option is to turn it around:
Dictionary<int,string> dict = new Dictionary<int,string>();
and do the search based on the value instead of the key. But that makes the code less readable and you dont really gain a lot from this.
If you are worried about the ID changing, I would recommend creating an Abstract Class to hold the ID values. This can be referenced like an Enum, and it will look up the ID on the first call, and cache the result:
public abstract class BillType
{
private static readonly string c_ok = "ok";
private static readonly string c_missing = "missing";
private static readonly string c_maximum = "maximum";
private static readonly string c_minimum = "minumum";
private static readonly string c_error = "error";
private static int? _ok = null;
private static int? _missing = null;
private static int? _maximum = null;
private static int? _minimum = null;
private static int? _error = null;
public static int OK
{
get
{
if (_ok == null)
_ok = GetBillTypeID(c_ok);
return (int)_ok;
}
}
public static int Missing
{
get
{
if (_missing == null)
_missing = GetBillTypeID(c_missing);
return (int)_missing;
}
}
public static int Maximum
{
get
{
if (_maximum == null)
_maximum = GetBillTypeID(c_maximum);
return (int)_maximum;
}
}
public static int Minimum
{
get
{
if (_minimum == null)
_minimum = GetBillTypeID(c_minimum);
return (int)_minimum;
}
}
public static int Error
{
get
{
if (_error == null)
_error = GetBillTypeID(c_error);
return (int)_error;
}
}
private static int GetBillTypeID(string identifier)
{
using (SqlConnection conn = new SqlConnection("your connection string")
{
conn.Open();
using (SqlCommand cmd = new SqlCommand("spGetBillTypeId", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("Description", identifier);
return Convert.ToInt32(cmd.ExecuteScalar());
}
}
}
}
I would also have a Stored Procedure on your database to do a lookup for that ID:
Create Procedure spGetBillTypeId (#Description Varchar (20))
As Begin
Select Id
From BillTypes
Where Description = #Description
End
With this, you can simply call BillType.Missing and it will pull the Id of missing, cache it, and return 2.
(Note, most of this was copy/paste, so mind random errors I didn't catch).
If you don't expect the values to change, however, and you are okay with making code changes if that does happen, you can simply make an Enum:
public enum BillType
{
OK = 1,
Missing = 2,
Maximum = 3,
Minimum = 4,
Error = 5
}
Related
So I need to create a feature for generating auto number with +1 increment for each transaction that is saved. So basic requirement is this auto number generated must not be duplicated.
Table being used is
AutoNumber | TransactionInv
---------- | ----------------
Id | Id
Code | TransactionNo
LastNumber |
Example record of table is
AutoNumber
Id | Code | LastNumber
1 | AN-INV | 17
1 | AN-PO | 20
TransactionInv
Id | TransactionNo
1 | 2017-00017
2 | 2017-00018
Current function that I create
public string GetAutoNo(string code, IRepository<AutoNumber, Guid> autoNumberRepository, IUnitOfWorkManager uow)
{
using (var scope = uow.Begin(new UnitOfWorkOptions() { Scope = TransactionScopeOption.Required, IsolationLevel = IsolationLevel.ReadUncommitted }))
{
var autoNumber = autoNumberRepository.Where(c => c.Id == Id && c.Code == code).OrderByDescending(c => c.LastNumber).FirstOrDefault();
if (autoNumber == null)
{
autoNumber = new AutoNumber();
autoNumber.Code = code;
autoNumber.LastNumber = 0;
}
double currentNumber = autoNumber.LastNumber + 1;
var isUsed = autoNumberRepository.FirstOrDefault(c => c.LastNumber == currentNumber);
if (isUsed == null)
{
autoNumber.LastNumber += 1;
autoNumberRepository.Insert(autoNumber);
scope.Complete();
return currentNumber.ToString("00000");
}
else
{
return GetAutoNo(code, autoNumberRepository, uow);
}
}
}
My current problem is when multi user saving the transaction in a milliseconds different then it will be duplicated. Things to be take note that will auto number duplicate :
transaction save processing time
user connection speed when save transaction
many user saving at the same time / many users accessing transaction table
There are solution that I haven't tried yet, which is holdlock / tablelock, but if I have many users I think this solution is not a good idea, that's why I still think whether any better idea for this ?
If you guys have a experience in doing the same thing, maybe can advice me the better approach for this function ? I really appreciate it.
Thanks
You can try to consider using Sequence Number, then use NEXT VALUE every time it is called.
By doing this you can avoid duplicate numbers.
I would like to know is if I have an excel file and I am trying to get data via linq query will this be posible?
Excel file format
+-----------------+-------------+
| Inputlocation | Inputvalue |
+-----------------+-------------+
| 1 | Hello |
+-----------------+-------------+
| 2 | World!!! |
+-----------------+-------------+
Now If I am using Linq query given below is it possible to get Inputvalue data
var fileName = #"C:\Users\jshah\Documents\Visual Studio 2013\Projects\QA_ExpScript\QA_ExpScript\Excel\Inputdata.xls";
string sheetName = "Input";
var book = new LinqToExcel.ExcelQueryFactory(fileName);
var users = from x in book.Worksheet(Input) select x;
foreach (var x in users)
{
Console.WriteLine(x["1"]);
}
I am trying to do here is where inputlocation is "1" give me Inputvalue which is "Hello". Am I on a correct way to specify the query?. Also I am using this again and again later in my code. So please give better solution for this.
You can use where clause to filter the data like this:-
var users = from x in book.Worksheet()
where x["Inputlocation"].Cast<int>() == 1
select x["Inputvalue"].Cast<string>();
Then you can simply iterate through users:-
foreach (var item in users)
{
Console.WriteLine(item.Inputvalue); //This will print "Hello"
}
Although IMHO its always better to create a matching type to avoid any exceptions that can occur by typos when specifying the column names.
public class User
{
public int Inputlocation { get; set; }
public string Inputvalue { get; set; }
}
and here is the query:-
var users = from x in book.Worksheet<User>()
where x.Inputlocation == 1
select x;
This is kinda same as I am doing but somewhat answering the question. But don't what which #RahulSingh is saying.
Also related to #Chris 1 in the code. And creator of this post is i think saying that he does not want to change anythhing in his function. The only change he wants is Console.WriteLine(x["1"]); or Console.WriteLine(x["2"]); to get Inputvalue
Reference to my post
I have a data in mysql and I want to display the data one by one everytime I click the button. How to do it?
string ConnectToServer = #"server=..*.;port=****; user id=sampleID; password=samplePW; database=sampleDB; pooling=false";
public void GetNames()
{
MySqlConnection NameConnector = null;
MySqlDataReader NameReader = null;
try
{
NameConnector = new MySqlConnection(ConnectToServer);
NameConnector.Open();
string Name = "SELECT * from sampleNames";
MySqlCommand NameCommand = new MySqlCommand(Name, NameConnector);
NameReader = NameCommand.ExecuteReader();
while (NameReader.Read())
{
Console.WriteLine(NameReader.GetInt32(0) + ": " + NameReader.GetString(1));
NameLabel.Text += NameReader.GetString("Names") + "\n";
}
}
catch (MySqlException NameException)
{
Console.WriteLine("error : (0)", NameException.ToString());
}
finally
{
if (NameReader != null)
{
NameReader.Close();
}
if (NameConnector != null)
{
NameConnector.Close();
}
}
}
private void ButtonName_Click(object sender, EventArgs e)
{
GetNames();
}
the output:
Name1
Name2
Name3
Name4
Name5
but I wan't is, the Name will appear one by one each time I click the button
like this:
click = output Name1
click = output Name2
click = output Name3
click = output Name4
click = output Name5
There are at least 2 ways of doing that depending on how real-time you need the data and how many DB calls do you want to make. here they are:
Option #1
Initialize a class level variable for names list and an index variable.
List<string> names = null;
int currentNameIndex = 0;
on the click handler, if names is null, populate the names variable with all names in the DB. display the first item as follows.
private void ButtonName_Click(object sender, EventArgs e)
{
if (names == null)
{
names = GetNames();
}
if (currentNameIndex < names.Count)
{
NameLabel.Text += names[currentNameIndex++];
}
}
the getnames need to be modified to return the list of names.
Option #2
Instead of retrieving the whole list in 1 DB call, you could change the SQL query to get the first record from the Table. (based on a Id or some key)
On a click, GetNames will retrieve only 1 record and display that.
On the next click it'll retrieve another record, but not the first ones.
This would typically involve a query involving a key column. Please post your table schema and I can answer with the Query.
an e.g. Query is
int currentNameId = -1; // class level variable.
query is
Select TOP 1 nameId, names from SampleNames Where NameId > currentNameId Order By NameId;
currentNameId = int.Parse(NameReader[nameId].ToString());
the above query assumes that nameId is a unique key and that values start from 0 or greater than -1, and that they are incremental. (identity PKs etc.)
as I mentioned, if you can provide the table structure, we can answer better.
Option #1 is efficient in DB calls but may potentially have stale data.
Option #2 is more chatty but has more real-time data than Option #1.
You are reading all records:
while (NameReader.Read())
If you want to read just one, try put all your connection outside the method and run
NameReader = NameCommand.ExecuteReader();
only once.
Then change
while (NameReader.Read())
to
NameReader.Read()
I have situation where a storeprocdure return collection, but I do not how the object structure because the query is very dynamic.
One query can return:
Id | Location | MarketSegment | ... n columns
and another can return
Id | Sales Rep | Location | Region | ... n columns
I am simply just return a "object" as you can see in the code below. I know this won't work, but how can I set it up so it does?
using (DbContext db = new Context())
{
var items = db.Database.SqlQuery<object>(
"SP #Param1, #Param2",
new SqlParameter("Param1", ped),
new SqlParameter("Param2", 25)
).ToList();
return Request.CreateResponse<List<object>>(HttpStatusCode.OK, items);
}
EDIT:
I don't know if showing the SP will help in anyways, except if I can explain it more.
Each columns are represented as Custom Fields. Users are able to create n numbers of Custom Fields. So If you run the SP for User1 and he has 5 custom fields, then each custom fields will be represented in Columns, but If User2 has 3 custom fields, only 3 columns will be represented. What I don't have control over is the Custom Field Name and number of custom fields.
If on SQL 2016 or newer, add "FOR JSON AUTO" to your query to return as JSON, e.g:
var json = db.Database.SqlQuery<string>("Select x, y, z FROM tbl FOR JSON AUTO").First();
Then use Json.Net to create a dynamic object using
var myDynamic = JObject.Parse(json)
You can't use SqlQuery<T> for custom fields.
Creates a raw SQL query that will return elements of the given generic
type. The type can be any type that has properties that match the
names of the columns returned from the query, or can be a simple
primitive type. - MSDN
But, you can use ExecuteReader to achieve that.
using (var db = new Context())
{
db.Database.Connection.Open();
var cmd = db.Database.Connection.CreateCommand();
cmd.CommandText = "SP #Param1, #Param2";
cmd.Parameters.Add(new SqlParameter("Param1", ped));
cmd.Parameters.Add(new SqlParameter("Param2", 25));
List<List<object>> items = new List<List<object>>();
var reader = cmd.ExecuteReader();
while (reader.Read())
{
var item = new List<Object>();
items.Add(item);
for (int i = 0; i < reader.FieldCount ; i++)
item.Add(reader[i]);
}
return Request.CreateResponse<List<object>>(HttpStatusCode.OK, items);
}
If you know what all the possible columns could be returned, there is no issue with using a class that has more properties than you need.
public class Data
{
public int ID {get;set;}
public string SalesRep {get;set;}//Simply will be empty in the first example, but populated in the second.
public string Location {get;set;}
}
We are using an extractor application that will export data from the database to csv files. Based on some condition variable it extracts data from different tables, and for some conditions we have to use UNION ALL as the data has to be extracted from more than one table. So to satisfy the UNION ALL condition we are using nulls to match the number of columns.
Right now all the queries in the system are pre-built based on the condition variable. The problem is whenever there is change in the table projection (i.e new column added, existing column modified, column dropped) we have to manually change the code in the application.
Can you please give some suggestions how to extract the column names dynamically so that any changes in the table structure do not require change in the code?
My concern is the condition that decides which table to query. The variable condition is
like
if the condition is A, then load from TableX
if the condition is B then load from TableA and TableY.
We must know from which table we need to get data. Once we know the table it is straightforward to query the column names from the data dictionary. But there is one more condition, which is that some columns need to be excluded, and these columns are different for each table.
I am trying to solve the problem only for dynamically generating the list columns. But my manager told me to make solution on the conceptual level rather than just fixing. This is a very big system with providers and consumers constantly loading and consuming data. So he wanted solution that can be general.
So what is the best way for storing condition, tablename, excluded columns? One way is storing in database. Are there any other ways? If yes what is the best? As I have to give at least a couple of ideas before finalizing.
Thanks,
A simple query like this helps you to know each column name of a table in Oracle.
Select COLUMN_NAME from user_tab_columns where table_name='EMP'
Use it in your code :)
Ok, MNC, try this for size (paste it into a new console app):
using System;
using System.Collections.Generic;
using System.Linq;
using Test.Api;
using Test.Api.Classes;
using Test.Api.Interfaces;
using Test.Api.Models;
namespace Test.Api.Interfaces
{
public interface ITable
{
int Id { get; set; }
string Name { get; set; }
}
}
namespace Test.Api.Models
{
public class MemberTable : ITable
{
public int Id { get; set; }
public string Name { get; set; }
}
public class TableWithRelations
{
public MemberTable Member { get; set; }
// list to contain partnered tables
public IList<ITable> Partner { get; set; }
public TableWithRelations()
{
Member = new MemberTable();
Partner = new List<ITable>();
}
}
}
namespace Test.Api.Classes
{
public class MyClass
{
private readonly IList<TableWithRelations> _tables;
public MyClass()
{
// tableA stuff
var tableA = new TableWithRelations { Member = { Id = 1, Name = "A" } };
var relatedclasses = new List<ITable>
{
new MemberTable
{
Id = 2,
Name = "B"
}
};
tableA.Partner = relatedclasses;
// tableB stuff
var tableB = new TableWithRelations { Member = { Id = 2, Name = "B" } };
relatedclasses = new List<ITable>
{
new MemberTable
{
Id = 3,
Name = "C"
}
};
tableB.Partner = relatedclasses;
// tableC stuff
var tableC = new TableWithRelations { Member = { Id = 3, Name = "C" } };
relatedclasses = new List<ITable>
{
new MemberTable
{
Id = 2,
Name = "D"
}
};
tableC.Partner = relatedclasses;
// tableD stuff
var tableD = new TableWithRelations { Member = { Id = 3, Name = "D" } };
relatedclasses = new List<ITable>
{
new MemberTable
{
Id = 1,
Name = "A"
},
new MemberTable
{
Id = 2,
Name = "B"
},
};
tableD.Partner = relatedclasses;
// add tables to the base tables collection
_tables = new List<TableWithRelations> { tableA, tableB, tableC, tableD };
}
public IList<ITable> Compare(int tableId, string tableName)
{
return _tables.Where(table => table.Member.Id == tableId
&& table.Member.Name == tableName)
.SelectMany(table => table.Partner).ToList();
}
}
}
namespace Test.Api
{
public class TestClass
{
private readonly MyClass _myclass;
private readonly IList<ITable> _relatedMembers;
public IList<ITable> RelatedMembers
{
get { return _relatedMembers; }
}
public TestClass(int id, string name)
{
this._myclass = new MyClass();
// the Compare method would take your two paramters and return
// a mathcing set of related tables that formed the related tables
_relatedMembers = _myclass.Compare(id, name);
// now do something wityh the resulting list
}
}
}
class Program
{
static void Main(string[] args)
{
// change these values to suit, along with rules in MyClass
var id = 3;
var name = "D";
var testClass = new TestClass(id, name);
Console.Write(string.Format("For Table{0} on Id{1}\r\n", name, id));
Console.Write("----------------------\r\n");
foreach (var relatedTable in testClass.RelatedMembers)
{
Console.Write(string.Format("Related Table{0} on Id{1}\r\n",
relatedTable.Name, relatedTable.Id));
}
Console.Read();
}
}
I'll get back in a bit to see if it fits or not.
So what you are really after is designing a rule engine for building dynamic queries. This is no small undertaking. The requirements you have provided are:
Store rules (what you call a "condition variable")
Each rule selects from one or more tables
Additionally some rules specify columns to be excluded from a table
Rules which select from multiple tables are satisfied with the UNION ALL operator; tables whose projections do not match must be brought into alignment with null columns.
Some possible requirements you don't mention:
Format masking e.g. including or excluding the time element of DATE columns
Changing the order of columns in the query's projection
The previous requirement is particularly significant when it comes to the multi-table rules, because the projections of the tables need to match by datatype as well as number of columns.
Following on from that, the padding NULL columns may not necessarily be tacked on to the end of the projection e.g. a three column table may be mapped to a four column table as col1, col2, null, col3.
Some multi-table queries may need to be satisfied by joins rather than set operations.
Rules for adding WHERE clauses.
A mechanism for defining default sets of excluded columns (i.e. which are applied every time a table is queried) .
I would store these rules in database tables. Because they are data and storing data is what databases are for. (Unless you already have a rules engine to hand.)
Taking the first set of requirements you need three tables:
RULES
-----
RuleID
Description
primary key (RuleID)
RULE_TABLES
-----------
RuleID
Table_Name
Table_Query_Order
All_Columns_YN
No_of_padding_cols
primary key (RuleID, Table_Name)
RULE_EXCLUDED_COLUMNS
---------------------
RuleID
Table_Name
Column_Name
primary key (RuleID, Table_Name, Column_Name)
I've used compound primary keys just because it's easier to work with them in this context e.g. running impact analyses; I wouldn't recommend it for regular applications.
I think all of these are self-explanatory except the additional columns on RULE_TABLES.
Table_Query_Order specifies the order in which the tables appear in UNION ALL queries; this matters only if you want to use the column_names of the leading table as headings in the CSV file.
All_Columns_YN indicates whether the query can be written as SELECT * or whether you need to query the column names from the data dictionary and the RULE_EXCLUDED_COLUMNS table.
No_of_padding_cols is a simplistic implementation for matching projections in those UNION ALL columns, by specifying how many NULLs to add to the end of the column list.
I'm not going to tackle those requirements you didn't specify because I don't know whether you care about them. The basic thing is, what your boss is asking for is an application in its own right. Remember that as well as an application for generating queries you're going to need an interface for maintaining the rules.
MNC,
How about creating a dictionary of all the known tables involved in the application process up front (irrespective of the combinations - just a dictionary of the tables) which is keyed on tablename. the members of this dictionary would be a IList<string> of the column names. This would allow you to compare two tables on both the number of columns present dicTable[myVarTableName].Count as well as iterating round the dicTable[myVarTableName].value to pull out the column names.
At the end of the piece, you could do a little linq function to determine the table with the greatest number of columns and create the structure with nulls accordingly.
Hope this gives food for thought..