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.
Related
This past week I was tasked with moving a PHP based database to a new SQL database. There are a handful of requirements, but one of those was using ASP.Net MVC to connect to the SQL database...and I have never used ASP.Net or MVC.
I have successfully moved the database to SQL and have the foundation of the ASP site set up (after spending many hours pouring through tutorials). The issue I am having now is that one of the pages is meant to display a handful of fields (User_Name, Work_Date, Work_Description, Work_Location, etc) but the only way of grabbing all of those fields is by combining two of the tables. Furthermore, I am required to allow the user to search the combined table for any matching rows between a user inputted date range.
I have tried having a basic table set up that displays the correct fields and have implemented a search bar...but that only allows me to search by a single date, not a range. I have also tried to use GridView with its Query Builder feature to grab the data fields I needed (which worked really well), but I can't figure out how to attach textboxes/buttons to the newly made GridView. Using a single table with GridView works perfectly and using textboxes/buttons is very intuitive. I just can't seem to make the same connection with a joined view.
So I suppose my question is this: what is the best way for me to combine these two tables while also still having the ability to perform searches on the displayed data? If I could build this database from scratch I would have just made a table with the relevant data attached to it, but because this is derived from a previously made database it has 12+ years of information that I need to dump into it.
Any help would be greatly appreciated. I am kind of dead in the water here. My inexperience with these systems is getting the better of me. I could post the code that I have, but I am mainly interested in my options and then I can do the research on my own.
Thanks!
It's difficult to offer definitive answers to your questions due to the need for guesswork.
But here are some hints.
You can say WHERE datestamp >= '2017-01-01' AND datestamp < '2018-01-01' to filter all the rows in calendar year 2017. Many variations on this sort of date range filter are available.
Your first table probably has some kind of ID number on each row. Let's call it first.first_id. Your second table probably has its own id, let's call it second.second_id. And, it probably has another id that identifies a row in your first table, let's call it second.first_id. That second.first_id is called a foreign key in the second table to the first table. There can be any number of rows in your second table corresponding to your first table via this foreign key.
If this is the case you can do something like this:
SELECT first.datestamp, first.val1, first.val2, second.val1, second.val2
FROM first
JOIN second ON first.first_id = second.first_id
WHERE first.datestamp >= '2018-06-01' AND first.datestamp < '2018-07-01'
AND (first.val1 = 'some search term' OR second.val1 = 'some search term')
ORDER BY first.datestamp
This makes a virtual table by joining together your two physical tables (FROM...JOIN...).
Then it filters the rows you want from that virtual table (FROM ...).
Then it puts them in the order you want (ORDER BY...).
Finally, it chooses the columns from the virtual table you want in your result set (SELECT ...).
SQL database servers (MySQL, SQL Server, postgreSQL, Oracle and the rest) are very smart about doing this sort of thing efficiently.
In Azure we have four Shards and i want to remove two of them as we do not need them anymore. The Data should be merged into the other two Shards.
I use a Listmap with GUIDs as Key to identifiy the Shard (in our application this is the UserId).
In the tutorials i only found samples to merge Shards with the Range type.
Is there a way to merge these type of shards in a faster way or do i have to write my own tool for this?
If the merge is performed automatically what will for example happen in the following case:
The GUID to identify the Shard is the UserId, now this data is moved from Shard A to Shard B. There is another Table called Comments which has the UserId as ForeignKey. The PrimaryKey in this Table is a classic numeric auto increment value. What will happen to those values if they are moved from Shard A to Shard B? Will they be inserted and a new ID is assigned to them or will this not work at all?
Also there is some local FileStorage invloved which uses IDs in the Path so i will have to write my own tool anyway i think.
For that I took a look at the ShardMapManager but did not fully understand how it works. In the ShardMappingsGlobal Table is a Column called MappingId. But this is not the Guid/UserId which is stored in the Shard Database. How do i get the actual Guid which is used to identify the shard, in my case the UserId?
I also did not find Methods to move data between Shards.
What i would do now is Transfer the Data between the Shards with a tool by myself and then use the ListShardMap.UpdateMapping Method to set a new Shard for the value.
At the end of the operation i would use ListShardMap.DeleteShard or is there a better way to do this?
EDIT:
I wrote my own tool to merge the shards but i get a strange exception now. here some code:
Guid userKey = Guid.Parse(userId);
ListShardMap<Guid> map = GetUserShardMap<Guid>();
try
{
PointMapping<Guid> currentMapping = map.GetMappingForKey(userKey);
PointMapping<Guid> mappingOffline = map.UpdateMapping(currentMapping, new PointMappingUpdate()
{
Status = MappingStatus.Offline
});
}
The UpdateMapping causes the following exception:
Store Error: Error 515, Level 16, State 2, Procedure __ShardManagement.spBulkOperationShardMappingsLocal, Line 98, Message: Cannot insert the value NULL into column 'LockOwnerId', table __ShardManagement.ShardMappingsLocal
I do not understand why there is even an insert? I checked for the mappingId in the local and global Shardmapping tables and the mapping is there so no insert should be required in my opinion. I also took a look at the Code of the mentioned stored procedure spBulkOperationShardMappingsLocal here: https://github.com/Azure/elastic-db-tools/blob/master/Src/ElasticScale.Client/ShardManagement/Scripts/UpgradeShardMapManagerLocalFrom1.1To1.2.sql
In the Insert statement the LockOwnerId is not passed as parameter so it can only fail.
Currently i work with a testsetup because i do not want to play on the productive system of course. Maybe i made a mistake there but to me everything looks good. i would be very grateful about any hint regarding this error.
In the tutorials i only found samples to merge Shards with the Range type. Is there a way to merge these type of shards in a faster way or do i have to write my own tool for this?
Yes, the Split-Merge tool can move data from both range and list shard maps. For a list shard map you can issue shardlet move requests for each key. The Split-Merge tool unfortunately has some complicated set up, last time it took me around an hour to configure. I know this is not great, I'll leave it up to you to determine whether it would take more or less time to write your own custom version.
There is another Table called Comments which has the UserId as ForeignKey. The PrimaryKey in this Table is a classic numeric auto increment value. What will happen to those values if they are moved from Shard A to Shard B? Will they be inserted and a new ID is assigned to them or will this not work at all?
The values of autoincrement columns are not copied over, they will be regenerated at the destination. So new ids will be assigned to these rows.
For that I took a look at the ShardMapManager but did not fully understand how it works. In the ShardMappingsGlobal Table is a Column called MappingId. But this is not the Guid/UserId which is stored in the Shard Database. How do i get the actual Guid which is used to identify the shard, in my case the UserId?
I would strongly suggest not trying to edit the ShardMapManager tables on your own, it's very easy to mess up. Editing ShardMapManager tables is precisely what the Elastic Database Tools library is designed to do.
You can update the metadata for a mapping by using the ListShardMap.UpdatePointMapping method. Just to be clear, this only updates the ShardMapManager tables' knowledge of where the data should be for the key. Actually moving the mapping must be done by a higher layer.
This is a high-level summary of what the Split-Merge service does:
Lock the mapping to prevent concurrent update from another shard map management operation
Mark the mapping offline with ListShardMap.UpdatePointMapping. This prevents data-directed routing with OpenConnectionForKey from being allowed to access data with that key. It also kills all current sessions on the shard to force them to reconnect, this ensure that there are no active connections operating on data with the now-offline key
Move the underlying data, using the Shard Map's SchemaInfo to determine which tables need to be moved
Update the mapping and mark it online with ListShardMap.UpdatePointMapping
Unlock the mapping
I am a newbie to Cassandra and my current project called for me to create a table with the following columns:
id uuid PRIMARY KEY,
connections list<text>,
username text
I am using Cassandra's IMapper interface to handle my CRUD operations. While I found documentation that describes how to use the Mapping component for basic operations here:
http://docs.datastax.com/en/developer/csharp-driver/2.5/csharp-driver/reference/mapperComponent.html
I could not find documentation that outlines how to add and remove items from the List column for a specific record using the Mapper component. I tried to retrieve the record from the database, update the entity and save the changes to the record but the record is not updated in the database. It remains the same after the Update. However, the insert operation works and it mirrors the entity down to the object in the list.
User user = await _mapper.SingleAsync<T>("where Name = " + name);
user.Addresses = user.Addresses.Concat(new string[] { address });
await _mapper.UpdateAsync<T>(user);
How should this scenario be handled in Cassandra?
You can use the plus (+) and minus (-) CQL operators to append / prepend or remove items from a list.
In your case it would be:
// When using parameters, use query markers (?) instead of
// hardcoded stringified values
User user = await _mapper.SingleAsync<User>("where id = ?", id);
await _mapper.UpdateAsync<T>(
"SET connections = connections + ? WHERE id = ?", newConnections, id");
Note that append and prepend operations are not idempotent by nature. So in particular, if one of these operation timeout, then retrying the operation is not safe and it may (or may not) lead to appending/prepending the value twice.
I think in order for this to work and be efficient you may need several things:
partial update
It is atomic and doesn't require you to fetch the record first. Also, specifying only the fields you want to update avoids passing unnecessary load on the wire and relieves the pressure on the compactor.
use CqlOperator.Append/CqlOperator.Prepend/CqlOperator.SubstractAssign
Which allow you to specify only the collection items you want to add/remove.
Both of these optimizations are available via the Table API, not sure about the Mapper.
I have a issue regarding Merge Replication. I have a table SETTINGS where in i store the settings of my software.
The schema of the table is ID ( PK) , Description , Value.
Suppose i have 15 rows in this table on my server.
Now i have applied filter on this table saying only the first 10 rows would replicate.
Now with this settings when i sync for the first time, i receive the 10 rows on my client (having subscription).
Then i add the remaining 5 on my client.
Now when i sync again it gives me a conflict saying that
A row insert at 'ClientServer.ClientDatabaseName' could not be
propagated to 'MyServer.ServerDatabaseName'. This failure can be
caused by a constraint violation. Violation of PRIMARY KEY constraint
'PK_SETTINGS'. Cannot insert duplicate key in object 'dbo.SETTINGS'.
The duplicate key value is (11).
What i don't understand is why is it trying to replicate something (row) which is outside the subset filter applied on that table ?? Please help guys.
Is this scenario not possible with Merge replication ?
https://msdn.microsoft.com/en-us/library/ms151775.aspx the link suggests that this is possible. But confused.
Filters created on for a merge article are evaluated only at the publisher. Changes made at the subscriber will always be propagated back to the subscriber, even if they are outside the filter criteria. However if the changes from the one subscriber do not meet the filtering criteria, then they will sit on the publisher, but not be replicated to all the other subscribers.
Is this a production scenario, or are you playing around with replication? If you do static filtering, which is what you have above, it is typically done on read-only type of tables. For example, a salesperson in the field may only need prices for products in their region. They are not expected to update this table. If you do dynamic filtering, for example, filtering based on HOSTNAME(), then you would only get data specific for that user. For example, a salesperson in the field would receive only their customer information. Thus, any updates to that information, unless it's shared across multiple salespersons, would propagate back up, and not flow to anyone else.
In your case, i would not recommend updating tables on the subscriber that have static filters, thus i suggest re-evaluating your filtering design to ensure you have the right filtering model for your scenario.
If i have a field in my db which clarify the type of the application .
takes two values 0 or 1
0 for web app and 1 for win app
and now there is some requirement in my business:
There are some win applications available to all users and some of
them belong to specific users .
What 's the best solution to handle this case .
adding new field to state whether it's public or private
or just adding new value to the same field say 2 to state it's private win app
If you haven't already it would probably be best to slip in a user, role, permission based security model to the database/system, thereby giving you the ability to specify a group of users that have access to a particular application, whether it be web or windows based
I'd say add a new column next to your AppId called PublicIndicatior
Oh and be sure to have a lookup table so people can see what 0 or 1 means, and foreign key it to your data table
Lookup Table:
AppTypeId, AppTypeDescription
0, WebApp
1, WinApp
Data Table:
Id, AppTypeId, PublicIndicator
1,0,1
etc
As Pope suggested above (I +1 him), the best scenario is to add in a new user table (or tables for roles etc if possible) and then link to that through either a new foreign key, or using the appid (assuming it is on your table and unique). Then when the boss comes back 3 weeks later and say, "that's great, but now can we restrict App99 to just the Accounts Dept" you are not going back to the drawing board.