concurrent user read and update to mysql using c# - c#

I have a problem on my program, by solving this issue, it maybe can be done by using singleton method. But, i read from some article, they said,it is not a good way to implement it as the asp.net application concurrent users might have a lot.
My problem is,system running number is base on the particular record in the database example:
document_type="INV" , document_year=2015 , document_month=04, document_running=0102.
document_type="INV" , document_year=2015 , document_month=05, document_running=0002.
Therefore, when user create a new record, the logic of getting the new running number as below:
Get the document type = "inv" , current year and current month,
If not found. create a new document type , year and month record with the running number 0001.
if found. running + 1.
now, the problem come out. my situation is 5 users received the record information
as when they pressed "save" button to create a new record:
- document_type="INV" , document_year=2015 , document_month=05, document_running=0002.
and 5 users get the same running number INV15-05-0003 ( after 0002 + 1).
By right, should be INV15-05-0003, INV15-05-0004, INV15-05-0005, INV15-05-0006 and INV15-05-0007.
how we should do to avoid if all users getting the wrong/outdated information.
hope you all able to understand on my poor english.
Regards,
MH

The only way I see is to use a lock on the method you are calling to do the database management.
public class Dal
{
private static object syncObject = new object();
public static void InsertUpdate(...)
{
lock (syncObject)
{
// 1. Get the document type = "inv" , current year and current month,
// 2. If not found. create a new document type , year and month record with the running number 0001.
// 3. if found. running + 1.
}
}
}

The simplest way you can get close to desired effect is to use Auto Incrementing for document_running field: https://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html.
Warning: Be aware, in this case your document_running is always going to be unique across all documents, not just for the records with the same type/year/month.
Alternative solution:
Use GUID as document_running field. The same warning applies.

Related

Check for existence of a certain table in access DB using C# OleDB connection

I'm struggling to find a valid answer to what I'm trying to find.
Basically, I want to check if for example:
"tableNO1" exists or if every other table exists...
By the way, I'm using Access 2002-2003 if that somehow helps :)
Do you think I should upgrade to the latest version?
Background:
I'm trying to create run-time buttons that each one of them has a DB table, and when I close my program the tables that I created for each run-time created button will be saved. After I launch the program again I should click a button that will add these buttons that have DB tables (Each one of them has a dedicated table). for example, if 9 run-time buttons were created in the program before - each of them will have a DB table. I will have a max 9 button and each of them will be named tableNO(n) n=number of table
when I click the button that creates run-time buttons for the first time, it will create a button called "tableNO1", the second time "tableNO2" will be created, and so on...
Thanks in advance.
Ok, there are several ways to do this, but I suggest this code:
public Boolean TableExist(string sTable)
{
using (OleDbConnection conn = new OleDbConnection(Properties.Settings.Default.AccessDB2))
{
conn.Open();
string[] sRestrict = new string[] {null,null,null,null};
sRestrict[2] = sTable;
DataTable MySchema = new DataTable();
MySchema = conn.GetSchema("Columns",sRestrict);
return (MySchema.Rows.Count > 0);
}
}
The above is also how you can get the schema (table def) as a table.
Thus, say
if (TableExist("tblHotels")
{
// your code here
}
Now, because you are possible (likely) using a loop, then you might consider for reasons of performance to pass a valid connection to the TableExist function, and thus for your loop not re-create a connection each time - as that will slow things down quite a bit.
Note that "many" often suggest doing this:
SELECT * FROM MSysObjects WHERE [Name] = 'tableNO1' AND Type = 1
The problem with above is by default, the MySysObjects requires elevated rights. The database can be opened, and then using security settings in access the rights to MySysOjbects can be changed - but it more work then the above code/function.

Is there a way to Clone one or many Entities (records) in Code

NOTE: at this time I am stuck on 2sxc v9.43.2 on this project.
After selecting a set of records from my Content Type, I need to be able to duplicate them changing 1 of the fields along the way. Here is my almost-working idea so far. The use case is simple, they have Programs that people can register for. They change each Season, but only a little (prices, dates/times, etc). And they need the Current Season live and unchanged while they edit the Next Season. So we are still in the fall season (EntityId 1732) with 97 active programs. We want to click a button and clone all 97 programs as is, but IN TO the new Next Season (1735 below).
Two questions:
if this way works, what syntax would work on ent/Attributes to delivery the "object" as needed in the fields.Add() line
is there another 2sxc way to do this? Some other variant of the App.Data.Create() method or some other method in the API? I just need to duplicate the record with 1 field (Season) changed?
is there a better way to do this in the latest versions of 2sxc, v11.7+ ?
// we are going to duplicate the current Season's programs in to the new season
// cheating for now, pre-made new 1735 in Seasons, current is 1732
var programs = AsDynamic(App.Data["Programs"])
.Where(p => ((List<DynamicEntity>)p.Season).First().EntityId == selectedSeason.EntityId);
// #programs.Count() // 97
foreach(var copy in programs)
{
var fields = new Dictionary<string, object>();
var ent = AsEntity(copy);
foreach(var attr in ent.Attributes)
{
if(attr.Key == "Season")
{
fields.Add(attr.Key, new List<int> { 1735 });
}
else
{
fields.Add(attr.Key, ent.GetBestValue(attr.Key)); // object??
}
}
App.Data.Create("Programs", fields);
}
There are at least 3 ways to clone
Simple way using edit-ui
hard way using c# / server api
Semi-hard way using REST api
The simple way is to use the edit ui. You can see an example in the replace-dialog, there is a copy button there. This would open the edit UI with an existing item, but tell it it's a copy, so on save it would create a new one.
Combine this with a prefill or something and I think you would be good to go.
The second way is using the App.Data.Create - your code looks fairly good. I assume it also works and you were just wondering if there was a 1-liner - or am I mistaken?
The last way is using JS REST. Basically write some JS that gets an item, changes the object (resets the id) and posts it back to the endpoint for saving.
Just stumbled upon situation where I needed to create entity and set its field value, which has type of another entity. If that's your question #1, you need to add there EntityGuid.
fields.Add(attr.Key, attr.EntityGuid);. That should bind one entity to another one.
And no, I didn't stumble upon better way to copy entity then just to create a new one. At least so far.

Unable to retrieve information from some of the WorkItem Fields in TFS

So these days I am trying to work with the TFS API. So far it was good, but all of a sudden.. I want to retrieve specific story's work items and their respective information using a search by ID method to pick the correct story. In order not to miss some important information I am doing SELECT * in my queries. I get the story, I get the Tasks.. But there seems to be problem with few of the fields - namely AreaPath, IterationPath and Type. As a primitive check I've written down some Console prints to check what's good and what's not - so if I uncomment any of the three previously named on execution this exception is thrown: A first chance exception of type 'Microsoft.TeamFoundation.WorkItemTracking.Client.FieldDefinitionNotExistException' occurred in Microsoft.TeamFoundation.WorkItemTracking.Client.dll.
Here is what I am trying to print out:
Console.WriteLine(target.Fields["Title"].Value);
Console.WriteLine(target.Fields["Description"].Value);
Console.WriteLine(int.Parse(target.Fields["Id"].Value.ToString()));
Console.WriteLine(target.Fields["AreaPath"].Value); //Problem 1
Console.WriteLine(target.Fields["IterationPath"].Value); //Problem 2
Console.WriteLine(int.Parse(target.Fields["AreaId"].Value.ToString()));
Console.WriteLine(int.Parse(target.Fields["IterationId"].Value.ToString()));
Console.WriteLine(target.Fields["State"].Value);
Console.WriteLine(target.Fields["Type"].Value.ToString()); //Problem 3
With or without ToString() nothing really changes.
Any suggestions ?
EDIT: They are not null, I've checked while in Debug mode, they all have assigned values.
Use CoreField or builtin getters:
Console.WriteLine(target.Fields[CoreField.Title].Value);
Console.WriteLine(target.Fields[CoreField.AreaPath].Value);
Console.WriteLine(target.State);
Console.WriteLine(target.Type.Name);

Generating unique ID for clients on a system running over a LAN in C#

I've a simple client registration system that runs over a network. The system is supposed to generate a unique three digit ID (primary key) with the current year concatenated (e.g. 001-2013). However, I've encountered the problem that the same primary keys being generated when two users from different computers (over a LAN) try to register different clients.
What if the user cancels the registration after an ID is already generated? I've to reuse that ID for another client. I've read about static variable but it didn't solve my problem. I really appreciate your ideas.
Unique and sequential IDs are hard to implement. To completely achive it you would have to serialize commiting creation of client information so ID generated only when data is actually stored, otherwise you'll endup with holes when something wrong happened during submittion.
If you don't need strict sequential numbers - giving out ranges of ID (1-22, 23-44,...) to each system is common approach. Instead of ranges you can give out lists of IDs to use ({1,3,233,234}, {235,236,237}) if you need to use as many IDs as possible.
Issue:
New item -001 is created, but not saved yet
New item -002 is created, but not saved yet
Item -001 is cancelled
What to do with ID -001?
The easiest solution is to simply not assign an ID until an item is definitely stored.
An alternative is, when finally saving an item, you look up the first free ID. If the item from step 2 (#2) is saved before the one from step 1, #2 gets ID -001. When #1 then gets saved, the saving logic sees that its claimed ID (-001) is in use, so it'll assign -002. So ID's get reassigned.
Finally you can simply find the next free ID when creating a new item. In the three steps described above, this'll mean you initially have a gap where -001 is supposed to be. If you now create a new item, your code will see -001 is unused and will assign that to the new item.
But, and that totally depends on your requirements which you didn't specify, now -001 was created later in time than -002, I do not know if that is allowed. Furthermore at any given moment you can have a gap in your numbering where an item has been cancelled. If it happens at the end of a reporting period, this will cause errors (-033, -034, -036).
You also might want to include an auto-incrementing primary key instead of this invoice number or whatever it is.

Maker-Checker functionality for asp.net

I'm creating a maker-checker functionality where, maker creates a record and it is reviewed by the checker. The record creation will not happen until the checker approves it. If the checker rejects it then it should be rolled back.
The idea which i know is create a temporary table of records which will hold the records to be created until the checker approves it. But this method will have 2X number of tables to be created to cover all functionalities.
What are the best practices to achieve this?
Is it something which can be done using Windows Work Flow.? (WWF)
Just add a few more columns to your db.
Status : Current status of record ( Waiting for approval, Approved,
Declined . etc)
Maker : Username or id
Checker : Username or id
Checker Approval/Rejection Time
Alternatively if you have lots of tables like this needs to maker/checker workflow you can add another table and reference all other record to this table.
Windows workflow foundation also could work for you but i persnoally find it difficult to use
If you want revisions for the recored you also need more columns. Such as Revision Number and IsLastRevision.
I dont know what you are using for accessing db and modifiying records. If you are using OR/M you might override Update and do revisions on all saves . For Example
void Update(Entity e )
{
Entity n = new Entity();
// Create a copy of e ( With AutoMapper for example or manually )
e.Current = true;
e.RevisionNumber += 1;
Update(e);
Insert(n);
}
In this case you will have two options:
Create two identical tables and use one table for approved data and one for requested data.
OR
You can create two rows for a user with TypeID(requested/approved). in this case user will create a request with typeID = requested when approver approved that request you simply override current approved record with new one otherwise simply mark requested row with rejected status.

Categories

Resources