Collection Initializer in .Net Framework


Collection Initializer in .Net Framework 3.0 onwards. Collection initializer gives a simple syntax to create instance of a collection.

  1. Collection initializer is new feature of C# 3.0.
  2. Collection initializer gives a simple syntax to create instance of a collection.
  3. Any object that is implementing System.Collections.Generic.ICollection<T>can be initialized with collection initializer.
Let us say, we have a class

Student.cs

1public class Student
2{
3    public string FirstName { getset; }
4    public string LastName { getset; }
5}

Now if we want to make collection of this class and add items of type student in that collection and retrieve through the collection, we need to write below code

Program.cs

01using System;
02using System.Collections.Generic;
03using System.Linq;
04using System.Text;
05namespace ConsoleApplication16
06{
07    class Program
08    {
09        static void Main(string[] args)
10        {
11            List<Student> lstStudent = newList<Student>();
12            Student std = newStudent();
13            std.FirstName = "Dhananjay";
14            std.LastName = "Kumar ";
15            lstStudent.Add(std);
16            std = newStudent();
17            std.FirstName = "Mritunjay ";
18            std.LastName = "Kumar";
19            lstStudent.Add(std);
20            foreach (Student resstd in lstStudent)
21            {
22                Console.WriteLine(resstd.FirstName);
23            }
24            Console.Read();
25        }
26 
27    }
28}


Output
image1.gif

In above code,

  1. An instance of List of Student is getting created.
  2. An instance of the Student is getting created.
  3. Using the Add method on the list, instance of being added to list of students.
  4. Using For each statement iterating through the list to get the values.
Now, if instance of Student class can be assigned to List of student at the time of creation of instance of list then we call it automatic collection initializer.

image2.gif

If we see the above syntax

  1. It is highly readable.
  2. It is single statement.
  3. Instance of Student class is getting added on the fly.
And we can retrieve the values as below, 

image3.gif

In retrieving implicit type local variable is being used to fetch the different instance of the student in list of student 

01List<Student> lstStudent = newList<Student>()
02{
03     newStudent{FirstName ="Dhananjay" ,LastName="Kumar"},
04     newStudent {FirstName ="Mritunjay", LastName ="Kumar"}
05};
06foreach (var r in lstStudent)
07{
08     Console.WriteLine(r.FirstName);
09}
10Console.Read();

Output
image4.gif

How it internally works?

A collection initializer invokes the ICollection<T>.Add(T) method for each specified element in order. In the above example , it will call 

ICollection<Student>.Add(instance of Student )
SMO allows you to manage all objects which lives in the Microsoft SQL Server. It allows you to create, drop or alter objects from your .NET application with a API with is really easy to use. Create a identical copy of a table in a SQL Server Database with SMO? My first thought was no problem at all. But after some minutes of thinking (and after I came to realize that there is no Copy method provided by the Table class) I recognized it will be much harder. The download link at the end of the article contains the sample code.
Introduction
To modify, create or delete a database object, every class (which represents a database entity like Table, Index and so on) contains a Alter, Drop and Create method. As i mentioned in my first article about SMO, the library has a hierarchical structure like the objects in SQL Server. Every object contains a property Parent, so a Database object will return a Server object when the property Parent is called. SMO also allows you to generate the SQL Script, simply call the Script method (which also is implemented by every database entity), it will return a string collection which contains the scripts. You will find a lot more information on MSDN.
Copy the database table
Back to our goal, copy a table with the whole structure. First a method has copy the table and all the columns.
private Table createTable(Table sourcetable)
{
Database db = sourcetable.Parent;
string schema = sourcetable.Schema;
Table copiedtable = new Table(db, sourcetable.Name + "_Copy", schema);
Server server = sourcetable.Parent.Parent;

createColumns(sourcetable, copiedtable);

copiedtable.AnsiNullsStatus = sourcetable.AnsiNullsStatus;
copiedtable.QuotedIdentifierStatus = sourcetable.QuotedIdentifierStatus;
copiedtable.TextFileGroup = sourcetable.TextFileGroup;
copiedtable.FileGroup = sourcetable.FileGroup;
copiedtable.Create();

return copiedtable;
}

private void createColumns(Table sourcetable, Table copiedtable)
{
Server server = sourcetable.Parent.Parent;

foreach (Column source in sourcetable.Columns)
{
Column column = new Column(copiedtable, source.Name, source.DataType);
column.Collation = source.Collation;
column.Nullable = source.Nullable;
column.Computed = source.Computed;
column.ComputedText = source.ComputedText;
column.Default = source.Default;

if (source.DefaultConstraint != null)
{
string tabname = copiedtable.Name;
  string constrname = source.DefaultConstraint.Name;
 column.AddDefaultConstraint(tabname + "_" + constrname);
column.DefaultConstraint.Text = source.DefaultConstraint.Text;
}

column.IsPersisted = source.IsPersisted;
column.DefaultSchema = source.DefaultSchema;
column.RowGuidCol = source.RowGuidCol;

if (server.VersionMajor >= 10)
{
column.IsFileStream = source.IsFileStream;
column.IsSparse = source.IsSparse;
column.IsColumnSet = source.IsColumnSet;
}

copiedtable.Columns.Add(column);
}
}
After all information and columns are set, the table can be created by calling Create. Since SMO supports different SQL Server versions, you will also have to handle this in your code! Unfortunately, there is no enum with the versions, so you have to check the VersionMajor property of the Server object.
Copy all attached objects
To have the similar structure in the new table, you will have also to copy the checks, indexes and foreign keys. If you need the identical functionality, you will also have to copy the triggers.
private void createChecks(Table sourcetable, Table copiedtable)
{
foreach (Check chkConstr in sourcetable.Checks)
{
string name = copiedtable.Name + "_"+ chkConstr.Name;
Check check = new Check(copiedtable, name);
check.IsChecked = chkConstr.IsChecked;
check.IsEnabled = chkConstr.IsEnabled;
check.Text = chkConstr.Text;
check.Create();
}
}

private void createForeignKeys(Table sourcetable, Table copiedtable)
{
foreach (ForeignKey sourcefk in sourcetable.ForeignKeys)
{
string name = copiedtable.Name + "_" + sourcefk.Name;
 ForeignKey foreignkey = new ForeignKey(copiedtable, name);
foreignkey.DeleteAction = sourcefk.DeleteAction;
foreignkey.IsChecked = sourcefk.IsChecked;
foreignkey.IsEnabled = sourcefk.IsEnabled;
foreignkey.ReferencedTable = sourcefk.ReferencedTable;
foreignkey.ReferencedTableSchema = sourcefk.ReferencedTableSchema;
foreignkey.UpdateAction = sourcefk.UpdateAction;

foreach (ForeignKeyColumn scol in sourcefk.Columns)
{
string refcol = scol.ReferencedColumn;
ForeignKeyColumn column =
new ForeignKeyColumn(foreignkey, scol.Name, refcol);
foreignkey.Columns.Add(column);
}

foreignkey.Create();
}
}

private void createIndexes(Table sourcetable, Table copiedtable)
{
foreach (Index srcind in sourcetable.Indexes)
{
if (!srcind.IsDisabled && (srcind.IsClustered ||
(!srcind.IsClustered && !srcind.IsXmlIndex)))
{
string name = copiedtable.Name + "_" + srcind.Name;
Index index = new Index(copiedtable, name);

index.IndexKeyType = srcind.IndexKeyType;
index.IsClustered = srcind.IsClustered;
index.IsUnique = srcind.IsUnique;
index.CompactLargeObjects = srcind.CompactLargeObjects;
index.IgnoreDuplicateKeys = srcind.IgnoreDuplicateKeys;
index.IsFullTextKey = srcind.IsFullTextKey;
index.PadIndex = srcind.PadIndex;
index.FileGroup = srcind.FileGroup;

foreach (IndexedColumn srccol in srcind.IndexedColumns)
{
IndexedColumn column =
 new IndexedColumn(index, srccol.Name, srccol.Descending);
column.IsIncluded = srccol.IsIncluded;
index.IndexedColumns.Add(column);
}

index.Create();
}
}
}
The creation of the indexes, checks and foreign keys is similar than the creation of the table itself. So now you only have to call the methods in the correct order to get the full copy.
Transactions and SMO
You can easily execute a set of operations in the same transaction scope, so if something fails, everything will be rolled back. If we take the sample from above and want to make shure, that the table will only be copied if everything can be copied, we simply add the TransactionScope object which does everything for us.
public Table Copy(Table sourcetable)
{
using(TransactionScope scope = new TransactionScope())
{
var copiedtable = createTable(sourcetable);

createChecks(sourcetable, copiedtable);
createForeignKeys(sourcetable, copiedtable);
createIndexes(sourcetable, copiedtable);

scope.complete();
}

return copiedtable;
}

To create a dll follow the below steps

Open 'Visual Studio' and select File -> Open -> New ->Project




Click on ok Button. Once you click on Ok 'Button' your Class Library looks as follows.




Now you can add you code what you need.Here I am taking one Return data type String function. This function I will use in another project (.aspx) and showing the Result in a TextBox.

namespace MyClassLibraryConsole
{

public class Class1
{
public string strfunction(string input)
{string strmessage = input;
return strmessage;
}
}
}
Now you have to call this function in another project.Add New (or)Existing Project to your Solution.Here i am adding Existing .aspwebpages to my solution as follows.


Once you added your New or Existing Project your Solution will looks as follows 



Adding created dll file to .asp solution:-
Ricght click on DllDemo(.asp) solution and click on the select 'Add Reference'.

Now you can find dialog Box.Select 3rd tab 'Projects'.Now can find your created ClassLibrary(dll) as 'MyClassLibraryconsole'.Select it and click 'OK' button.

Now your dll is added successfully to your website.You can see your added dll in solution Explorer.

Calling dll file function in .aspx.cs page:-

protected void Button1_Click(object sender, EventArgs e)
{
MyClassLibraryConsole.Class1 obj = new MyClassLibraryConsole.Class1();
TextBox1.Text = obj.strfunction("Hellow World");
}

Showing the Result in TextBox

Introduction

This article talks about 6 ways of doing locking in .NET. It starts with concurrency problems and then discusses about 3 ways of doing optimistic locking. As optimistic locking does not solve the concurrency issues from roots, it introduces pessimistic locking. It then moves ahead to explain how isolation levels can help us implement pessimistic locking. Each isolation level is explained with sample demonstration to make concepts clearer.
This is a small Ebook for all my .NET friends which covers topics like WCF,WPF,WWF,Ajax,Core .NET,SQL, Entity framework, Design patterns , Agile etc you can download the same from here  or else you can catch me on my daily free training @ from here

  
Why do we need locking?

In multi-user environment it's possible that multiple users can update the same record at the same time causing confusion between users. This issue is termed as concurrency.

How can we solve concurrency problems?

Concurrency problems can be solved by implementing proper "Locking strategy". Locks prevent action on a resource to be performed when some other resource is already performing some action on it.

What kind of confusion is caused because of concurrency?

There are 4 kinds of major problems caused because of concurrency, below table shows the details of the same.

ProblemsShort descriptionExplanation
Dirty reads"Dirty Read" occurs when one transaction is reading a record, which is part of a half, finished work of other transaction.. User A and user B are seeing value as "5".
. User B changes the value "5" to "2".
. User A is still seeing the value as "5"..Dirty read has happened.
Unrepeatable readIn every data read if you get different values then it's an "Unrepeatable Read" problem.. User A is seeing value as "5".
. User B changes the value"5" to "2".
. User A refreshes see values "5", he is surprised..unrepeatable read has happened.
Phantom rowsIf "UPDATE" and "DELETE" SQL statements does not affect the data then it can be "Phantom Rows" problem.. User A updates all value "5' to "2".
. User B inserts a new record with value "2".
. User A selects all record with value "2' if all the values have changed, he is surprised to still find value "2" records...Phantom rows have been inserted.
Lost updates"Lost Updates" are scenario where one updates which is successfully written to database is overwritten with other updates of other transaction.. User A updates all value form "5" to "2".
. User B comes and updates all "2" values to "5".
. User A has lost all his updates.

So how can we solve the above problems?

By using optimistic or pessimistic locking, the further coming article discusses the same.

What is Optimistic locking?


As the name suggests "optimistic" it assumes that multiple transaction will work without affecting each other. In other words no locks are enforced while doing optimistic locking. The transaction just verifies that no other transaction has modified the data. In case of modification the transaction is rolled back.

How does optimistic lock work?

You can implement optimistic locking by numerous ways but the fundamental to implement optimistic locking remains same. It's a 5 step process as shown below:-
. Record the current timestamp.

. Start changing the values.

. Before updating check whether anyone else has changed the values by checking the old time stamp and new time stamp.

. If it's not equal rollbacks or else commit.


What are the different solutions by which we can implement optimistic locking?

There are 3 primary ways by which we can implement optimistic locking in .NET:-

Datasets: - Dataset by default implement optimistic locking. They do a check of old values and new values before updating.

Timestamp Data type: - Create a timestamp data type in your table and while updating check if old timestamp is equal to new timestamp.

Check old and new value: - Fetch the values, do the changes and while doing the final updates check if the old value and current values in database are equal. If they are not equal then rollback or else commits the values.

Solution number 1:- Datasets

As said in the previous section dataset handles optimistic concurrency by itself. Below is a simple snapshot where we held the debug point on Adapter's update function and then changed the value from the SQL Server. When we ran the "update" function by removing the break point it threw "Concurrency" exception error as shown below.


If you run the profiler at the back end you can see it fires the update statement checking of the current values and the old values are same.
exec sp_executesql N'UPDATE [tbl_items] SET [AuthorName] = @p1 WHERE (([Id] =
@p2) AND ((@p3 = 1 AND [ItemName] IS NULL) OR ([ItemName] = @p4)) AND ((@p5 =
1 AND [Type] IS NULL)
OR ([Type] = @p6)) AND ((@p7 = 1 AND [AuthorName] IS NULL) OR ([AuthorName] =
@p8)) AND ((@p9 = 1 AND [Vendor] IS NULL) OR ([Vendor] = @p10)))',N'@p1
nvarchar(11),@p2 int,@p3
int,@p4 nvarchar(4),@p5 int,@p6 int,@p7 int,@p8 nvarchar(18),@p9 int,@p10
nvarchar(2)',@p1=N'this is new',@p2=2,@p3=0,@p4=N'1001',@p5=0,@p6=3,@p7=0,@p8=N'This is Old
Author',@p9=0,@p10=N'kk'
In this scenario we were trying to change the field value "AuthorName" to "This is new" but while updating it makes a check with the
 old value "This is old author". Below is the downsized code snippet of the above SQL which shows the comparison with old value.
,@p8=N'This is Old Author'

Solution number 2:- Use timestamp data type

The other way of doing optimistic locking is by using 'TimeStamp' data type of SQL Server. Time stamp automatically generates
a unique binary number every time you update the SQL Server data. Time stamp data types are for versioning your record updates.


To implement optimistic locking we first fetch the old 'TimeStamp' value and when we are trying to update we check if the old time
stamp is equal to the current time stamp as shown in the below code snippet.
update tbl_items set itemname=@itemname where CurrentTimestamp=@OldTimeStamp
We then check if any updates has happened, in case updates has not happened then we raise a serious error '16' using SQL Server 'raiserror'
as shown in the below code snippet.
if(@@rowcount=0)
begin
raiserror('Hello some else changed the value',16,10)
end
If any concurrency violation takes place you should see the error propagated when you call 'ExecuteNonQuery' to the client side as
shown in the below figure.


Solution number 3:- Check old values and new values

Many times we would like to check concurrency on only certain fields and omit fields like identity etc. For those kind of scenarios
we can check the old value and the new value of the updated fields as shown in the below code snippet.
update tbl_items set itemname=@itemname where itemname=@OldItemNameValue

But it looks like by using optimistic locking concurrency problems are not really solved?

Yes, you said right. By using optimistic locking you only detect the concurrency problem. To solve concurrency issues from the roots
itself we need to use pessimistic locking. Optimistic is like prevention while pessimistic locking is actually the cure.

What is pessimistic locking?



Pessimistic locking assumes that concurrency / collision issues will happen so a lock is placed on the records and then data is updated.

How can we do pessimistic locking?

We can do pessimistic locking by specifying "IsolationLevel" in SQL Server stored procedures, ADO.NET level or by using transaction scope object.

What kind of locks can be acquired by using pessimistic locking?

There are 4 kinds of locks you can acquire Shared, Exclusive, Update and intent. The first two are actual locks while the other two
are hybrid locks and marker.

 When to use?Reads AllowedWrites Allowed
Shared lockWhen you want only to read and you do not want any other transactions to do update.YesNo
ExclusiveWhen you want to modify data and you do not want anyone to read the transaction, neither you want anyone to update.NoNo
Update lockThis is a hybrid lock. This lock is used when you want to do update operation which passes through multiple phases before the actual update happens. It first starts with shared lock in the read phase and then on the actual update it acquires an exclusive lock.  
 Read phaseYesNo
 Manipulating phaseYesNo
 Update phasNoNo
Intent Lock ( Demand locks)Intent lock is for lock hierarchy. This lock is used when you want to lock resources down in the hierarchy. For example a shared intent lock on a table means shared locks are placed on pages and rows with the table.NANA
Schema locksWhen you are changing table structure.NoNo
Bulk update locksUsed when you are doing bulk updatesTable level NoTable level No

The update lock is confusing can you explain in detail?

The other locks are pretty straight forward; the update lock is confusing because of its hybrid nature. Many times before we update we read the record. So during read the lock is shared and while actually updating we would like to have an exclusive lock. Update locks are more of transient locks.


So what are the different types of isolation levels and when should be used when?

There are 4 kinds of transaction isolation level, below is a simple table which shows when to use them and what locks they put.
Isolation LevelReadUpdateInsert
Read UncommittedReads data which is yet not committed.AllowedAllowed
Read Committed ( Default)Reads data which is committed.AllowedAllowed
Repeatable ReadReads data which is committed.Not AllowedAllowed
SerializableReads data which is committed.Not AllowedNot Allowed

How can we specify Isolation?

Isolation levels are features of RDBMS software, in other words they fundamental really belong to SQL Server and not to Ado.NET, EF or LINQ. Said and done that you can always set the transaction isolation level from any of these components.


Middle tier
In middle tier you can specify isolation level using transaction scope object.
TransactionOptions TransOpt = New TransactionOptions();
TransOpt.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
using(TransactionScope scope = new
TransactionScope(TransactionScopeOption.Required, TransOptions))
{

}
ADO.NET
You can also specify transaction isolation level using "SqlTransaction" object in ADO.NET.
SqlTransaction objtransaction = 
objConnection.BeginTransaction(System.Data.IsolationLevel.Serializable);
SQL Server
You can also specify isolation level in TSQL using 'SET TRANSACATION ISOLATION LEVEL' as shown in the below code snippet.
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

Which transaction isolation level solves which problems from Concurrency?

Below is a chart which shows which transaction isolation level solves which problems of concurrency.

 Read committed(S)Repeatable read(I)   SerializableRead Uncommitted
Dirty reads
        Solves
        Solves    Solves            X
Lost updates            X        Solves    Solves            X
Non repeatable reads            X        Solves    Solves            X
Phantom rows            X              X    Solves            X

Solution 4:- Can we see how dirty reads are solved using Read Committed?

Some important Key points about read committed:-

. It's the default transaction isolation level for SQL Server.

. Its reads only committed data. In other words any uncommitted data is not read and blocked until the commit happens. Below figure explains the same in more detail. You can see the update


If you want the see above things practically do the following:-
. Open 2 Query windows fire an update transaction but do not commit.

. In the second window try firing select query it will show a blocked query as shown in the below figure.


So is Read uncommitted opposite of Read Committed?

Yes, read uncommitted is opposite to read committed. When you set the transaction isolation level to read uncommitted, uncommitted data is also read.
Some important key points for read committed:-

. Uncommitted is see so dirty read possible.

. No locks held.

. Useful when locking is not important and more important is concurrency and throughput.

If you want to test the same, fire the below SQL statement which is doing an update and roll back. The roll back happens after 20 seconds halt. Within that time if you fire a select query you will get the uncommitted data and after 20 seconds you will see the old data this committed data is rolled back.
set transaction isolation level read uncommitted
Begin Tran

Update customer set CustomerName='Changed' where CustomerCode='1001'
WAITFOR DELAY '000:00:20'
rollback tran
set transaction isolation level read uncommitted
select * from Customer where CustomerCode='1001'

Solution 5:- Can we see how lost update and non-repeatable read are solved using repeatable read?

By setting isolation level to repeatable read no one can read and update the data. Some key points about repeatable read isolation level are as follows:-
. Only committed data is read when repeatable transaction isolation level is set for select queries.

. When you select a record using repeatable read no one other transaction can update the record. , but selects are possible.

. If repeatable transaction is set in update query, until the transaction finishes no one can read or update the same.

. When select and update query is set to repeatable read other transaction can insert new records. In other words phantom rows are possible.

If you want to test this isolation level, fire the below syntax and try firing select and update queries they will be blocked and after 50 seconds you should see the data.
set transaction isolation level repeatable read
Begin Tran
Update customer set CustomerName='Changed' where CustomerCode='1001'
WAITFOR DELAY '000:00:50'
rollback tran
If you fire the below select query in repeatable read mode you will not be able to update for 50 seconds until the transaction finishes.
set transaction isolation level repeatable read
begin tran
select * from Customer where CustomerCode='1001'
WAITFOR DELAY '000:00:50'
commit tran
One important note you can add new records of customer code 1001, in other words phantom rows are possible.

Solution 6:- How are Phantom row problems addressed using Serializable Isolation level?

This is the highest level of isolation level; in this other transactions cannot update, select and insert records.
Some key points for serializable transaction are:-

. No other transaction can insert, update, delete or select when isolation level is serializable.

. Lot of blockings but all concurrency issues are solved.
set transaction isolation level serializable
begin tran
select * from Customer where CustomerCode='1001'
WAITFOR DELAY '000:00:50'
commit tran

In what scenarios should we use optimistic and pessimistic locking?

Request to Write

We are looking for the people who believes in sharing the knowledge.
If you are interested in writing on this blog please COMMENT  on the post and write your name, email address and the small introduction about you, so that we can send you rights.






Thanks
We-The People  
top