Where should I manage the createdBy, modifiedBy, createDate, and modifiedDate? - asp.net

I want to insert the createdBy, modifiedBy, createDate, modifiedDate columns in every database table for manage user activity.
This is the first time I try to do this. Is there a best practice I could follow? Any design pattern good to manage this?
My first thought is to do this in my business logic layer, and in every business classes' insert and update method, i do something like this:
class.createDate = DateTime.Now;
or
class.modifiedDate= DateTime.Now;
class.modifiedBy = CurrentUser.Id;
or
class.createdBy = CurrentUser.Id;
Or there are much better way?
Bryan

This depends on what types of business objects you are managing, and what the rules are around what the create/modified data is needed for. In most cases, this is a database audit trail, and there is no need for this information in the business logic layer. In that case, this information should live at the database level only. If you are using an ORM, that might mean you keep the data with your objects anyway. If you are using stored procs, then they all need to know how to take a user name to tag the record with. The datetimes can be handled by setting a default value of GetDate() on the column.

Well one thing to consider is what time do you want stamped? Do you want the time of the application server or the time on the database server? I always go for the DB server. So in that case the stored procedure (or SQL statements) should be getting current time.
-Krip

You should manage CreatedDate and ModfiedDate at database label only. Default value of the CreatedDate should be Getdate()/SYSDATE and you don’t need to set this value. For ModifiedDate again set the GETDATE()/SYSDATE on every update.
You only need to pass the ModifiedBy userid from your application to the database, in case of insert set the userid for both the column and in the case of update only update the Modified by userId column.

For createdBy and modifiedBy, I usually set this in my business layer using the username of the current user. For createDate and modifiedDate I do this in the 'after' triggers in the database.

Related

Pre run SQL query to be used by ASP.net application

I have a SQL query which is running on a view and on top has lot of wild card operators, hence taking a lot of time to complete.
The data is consumed by an ASP.net application, is there any way I could pre-run the query once in a day so data is already there when asp.net application needs it and only pass on the parameter to fetch specific records.
Much simplified example would be
select * from table
Run every day and result stored somewhere and when asp.net passes on the parameter only specific records are fetched like
select * from table where field3 = 'something'
Either use SQLAgent (MSSQL) or equivalent to run a scheduled process that stores the result into a Table like this...
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[MyTemporaryTable]') AND type in (N'U'))
BEGIN
TRUNCATE TABLE [dbo].[MyTemporaryTable];
INSERT INTO [dbo].[MyTemporaryTable]
SELECT * FROM [vwMyTemporaryTable];
END
ELSE
BEGIN
SELECT *
INTO [MyTemporaryTable]
FROM [vwMyTemporaryTableDataSource];
END
or you could store the result in ASP.Net as an Application/Session variable or even a Property in a class that is stored in Application/Session. The Property approach will load the data the first time it is requested, and use memory thereafter.
private MyObjectType _objMyStoredData;
public MyObjectType MyStoredData
{
get
{
if (_objMyStoredData == null)
{
_objMyStoredData = GetMyData();
}
return _objMyStoredData;
}
}
However, if your source data for this report is only 2,000 rows... I wonder if all this is really necessary. Perhaps increasing the efficiency of the query could solve the problem without delving into pre caching and the downsides that go with it, such as re-using data that could be out of date.
You can use redis. You can run the view once the user logs in. Then fill redis with the view data. Set that object in Session Context of user so that it is accessible on all pages. Then when the user logs out. clean up the redis. By this way user won't go to database everytime for result instead will get the data from redis cache. it's very fast. You can contact me if more help is needed.
you can mark it as answer if you find it helpful.

ASP.NET Membership Profile

I want to send out an email to all users where their birthday is today
I am using the built-in asp.net (3.5) membership. All users have a profile (stored in aspnet_Profile) which contains a date/time property called 'birthday'. I need to get a list of users email addresses from the 'aspnet_Membership' table where a users birthday is today, along with the users 'firstname' which is string property in the aspnet_Profile table.
I would like a list returned preferrably using C# LINQ.
I am not sure how to access the birthday property in the profile table, based on the way it is stored in the db table i.e name/value columns
I think you should consider changing to the much-improved table based provider:
http://weblogs.asp.net/scottgu/archive/2006/01/10/435038.aspx
This allows you to separate your data into one value per table column in the standard SQL way. This performs petter than the standard provider and it solves your problem of querying the Profiles database.
It will take a small amount of work to convert the database, but on the code side, it is just a matter of configuring in a different provider and nothing else should change. That is the beaurty of the provider pattern.
I don't use LINQ enough to give you a good answer, but the following may be the underlying SQL you need (This is how my SSMS generated it in the query designer):
SELECT aspnet_Profile.PropertyValuesString AS firstname, aspnet_Membership.Email
FROM aspnet_Profile INNER JOIN
aspnet_Membership ON aspnet_Profile.UserId = aspnet_Membership.UserId INNER JOIN
aspnet_Profile AS aspnet_Profile_1 ON aspnet_Profile.UserId = aspnet_Profile_1.UserId
WHERE (aspnet_Profile_1.PropertyNames LIKE N'birthday') AND (aspnet_Profile.PropertyNames LIKE N'firstname') AND (DATEADD(dd, 0, DATEDIFF(dd, 0,
aspnet_Profile_1.PropertyValuesString)) = DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE())))
The Profile mechanism parses the values out by splitting each name/value pair up, and then parsing them individually. You could write code to do that yourself. Or you could follow #Daniel's approach and use the alternative provider, which makes life easier. The out-of-the-box provider is a pain with the string concatenation.
Is this code in the same app? You could just use the profile object to retrieve it, if you are talking C#... what context is this piece of code in? Batch service?

insert data from a asp.net form to a sql database with foreign key constraints

i have two tables
asset employee
assetid-pk empid-pk
empid-fk
now, i have a form to populate the asset table but it cant because of the foreign key constraint..
what to do?
thx
Tk
Foreign keys are created for a good reason - to prevent orphan rows at a minimum. Create the corresponding parent and then use the appropriate value as the foreign key value on the child table.
You should think about this update as a series of SQL statements, not just one statement. You'll process the statements in order of dependency, see example.
Asset
PK AssetID
AssetName
FK EmployeeID
etc...
Employee
PK EmployeeID
EmployeeName
etc...
If you want to "add" a new asset, you'll first need to know which employee it will be assigned to. If it will be assigned to a new employee, you'll need to add them first.
Here is an example of adding a asset named 'BOOK' for a new employee named 'Zach'.
DECLARE #EmployeeFK AS INT;
INSERT (EmployeeName) VALUES ('Zach') INTO EMPLOYEE;
SELECT #EmployeeFK = ##IDENTITY;
INSERT (AssetName, EmployeeID) VALUES ('BOOK',#EmployeeFK) INTO ASSET;
The important thing to notice above, is that we grab the new identity (aka: EmployeeID) assigned to 'Zach', so we can use it when we add the new asset.
If I understand you correctly, are you trying to build the data graph locally before persisting to the data? That is, create the parent and child records within the application and persist it all at once?
There are a couple approaches to this. One approach people take is to use GUIDs as the unique identifiers for the data. That way you don't need to get the next ID from the database, you can just create the graph locally and persist the whole thing. There's been a debate on this approach between software and database for a long time, because while it makes a lot of sense in many ways (hit the database less often, maintain relationships before persisting, uniquely identify data across systems) it turns out to be a significant resource hit on the database.
Another approach is to use an ORM that will handle the persistence mapping for you. Something like NHibernate, for example. You would create your parent object and the child objects would just be properties on that. They wouldn't have any concept of foreign keys and IDs and such, they'd just be objects in code related by being set as properties on each other (such as a "blog post" object with a generic collection of "comment" objects, etc.). This graph would be handed off to the ORM which would use its knowledge of the mapping between the objects and the persistence to send it off to the database in the correct order, perhaps giving back the same object but with ID numbers populated.
Or is this not what you're asking? It's a little unclear, to be honest.

Cannot insert null where field is Guid (object in SqlDataSource)

I have a table which links to another table in the ASP.NET membership schema.
Problem is, all the PKs for the ASP.NET tables are uniqueidentifier so mine has to be too. When I add a SqlDatasource and call its Insert() method, I get the following error:
Cannot insert the value NULL into column 'DiscountCode', table 'CreamDb.dbo.CustomInfo1'; column does not allow nulls. INSERT fails.
The statement has been terminated.
The uniqueidentifier is also treated as an object (its data type), but there is no Guid data type. I had this problem before, but the schema was much simpler so I could fix it.
How can I go about fixing this? If I get rid of the data type part in the markup (so just leave the field/parameter name but not the data type stuff), I get another error so that is not possible.
Thanks
What do you mean by "there is no Guid data type"? What's wrong with System.Guid? Can't you just use Guid.NewGuid(), set the field appropriately, and do the insert?
EDIT: Just to give a bit more meat: attach an event handler to the Inserting event, and populate the field then, via the DbCommand returned by SqlDataSourceCommandEventArgs.Command. Or change the SQL used by the INSERT command to ask the database to populate the GUID field for you.
A popullar approach when dealing with references to the ASP.NET Membership Provider's data is, instead of keeping a proper foreign key to the GUIDs, instead store something like the LoweredUserName in your table. Then, use the Membership Provider's API to interact with the object you need. In some cases, you need an ObjectDataSource abstraction layer to accomplish CRUD scenarios.
Set the default value of the column in SQL Sever to "newid()".
Asp.net won't send the value, and the field will get a new guid.

How to Get Last Created Entry's ID From Sql Database With Asp.Net

I will explain problem with an example:
There is two table in my database, named entry, tags
There is a column named ID_ENTRY in both table. When I add a record to table, entry, I have to take the ID_ENTRY of last added record and add it to table, tags. How can I do it?
The only way to do this is with multiple statements. Using dynamic sql you can do this by separating each statement in your query string with a semi-colon:
"DECLARE #ID int;INSERT INTO [Entry] (...) VALUES ...; SELECT #ID = scope_identity();INSERT INTO [TAGS] (ID_ENTRY) VALUES (#ID);"
Make sure you put this in a transaction to protect against concurrency problems and keep it all atomic. You could also break that up into two separate queries to return the new ID value in the middle if you want; just make sure both queries are in the same transaction.
Also: you are using parameterized queries with your dynamic sql, right? If you're not, I'll personally come over there and smack you 10,000 times with a wet noodle until you repent of your insecure ways.
Immediatly after executing the insert statement on first table, you should query ##IDENTITY doing "SELECT ##identity". That will retrieve the last autogenerated ID... and then just insert it on the second table.
If you are using triggers or something that inserts rows... this may be not work. Use Scope_Identity() instead of ##IDENTITY
I would probably do this with an INSERT trigger on the named entry table, if you have all of the data you need to push to the tags table available. If not, then you might want to consider using a stored procedure that creates both inside a transaction.
If you want to do it in code, you'll need to be more specific about how you are managing your data. Are you using DataAdapter, DataTables, LINQ, NHibernate, ...? Essentially, you need to wrap both inserts inside a transaction of some sort so that either inserts get executed or neither do, but the means to doing that depend on what technology you are using to interact with the database.
If you use dynamic sql, why not use Linq to Entity Framework, now EF is the recommend data access technology from Microsoft (see this post Clarifying the message on L2S Futures from ADO.NET team blog), and if you do an insert with EF the last identity id will available for you automatically, I use it all the time it's easy.
Hope this helps!
Ray.

Resources