Devart Blog

Entity Framework: Tips and Tricks, part 3

Posted by on October 19th, 2010

This article continues series of publications about non-trivial Entity Framework situations encountered by our users.

We consider the following questions in this article:


1. Why Oracle raises an exception about too many local sessions participating in global transaction when using TransactionScope?

Issue:

I have run the following test code:

public void TestMaxNumberOfObjectContetxtInTransactionScope()
{
   using (TransactionScope ts = new 
      TransactionScope(TransactionScopeOption.Required, 
      IsolationLevel.ReadCommitted))
      {
          for (int i = 0; i < 50; i++)
          {
              using (TestObjectContext context = new TestObjectContext())
             {
                 TestData newTestData = TestData.CreateTestData(id);
                 newTestData.Description = description;
                 context.AddToTestDataEntity(newTestData);
                 context.SaveChanges();
             }
           }
           ts.Complete();
       }
}

and it failed after the 32 iterations. The error I get is “ORA-02045: too many local sessions participating in
global transaction”. One more strange thing is the fact that everything works like a charm in Direct mode.
Could you please explain the behaviour?

Solution:

Maximum number of branches in the distributed Oracle transaciton is 32. We use distributed Oracle transactions in our code that implements TransactionScope support. So, as soon as the number of transactions inside the scope exceeds this number this error appears. The reason of the fact that Direct mode works is the fact that there is no distributed transactions support in it (local transactions are used). So, the workaround is to use TransactionScope with smaller number of transaction branches. In most scenarios it is enough to use a local transaction like in the following example:

context.Connection.Open();
DEPT department = context.DEPT.Where(d => d.DEPTNO == 10).First();
department.LOC = "TEST";

using (System.Data.Common.DbTransaction transaction = 
   context.Connection.BeginTransaction()) {
   context.SaveChanges();
   department.DNAME = "TEST";
   context.SaveChanges();

   if (flag)
      transaction.Commit();
   else
      transaction.Rollback();
 }

Note: Starting from the last version of dotConnect for Oracle we solve this problem with the help of promotable single phase transaction support. Only one active session with internal local transaction is used during several connections opening. You can activate this option in connection string setting up the parameter “Transaction Scope Local=true”.

2. How can I optimize SQL queries using Entity Framework?

Issue:

When I am using native SQL I can easily use hints for MySQL optimization. Can I use anything like this when using Entity Framework?

Solution:

You have two alternatives – the first one is to create views in your database implementing the desired behaviour, and the second one is to manually create Defining Query in the Storage model and entities in your conceptual model corresponding to these Defining Queries.

In both cases you will be able to use the MySQL hints.

3. How can I perform cascade deleting of objects in Entity Framework?

Issue:

Do I really have to delete all child entities separately? Is there any possibility to use cascaded deletes?

Solution:

Add Cascade action for all associations you want to be cascaded. This action should be added both in CSDL and SSDL parts of the .edmx file. Here is an example of CSDL part:
<Association Name="CProductCategory">
    <End Type="Self.CProduct" Multiplicity="*" />
       <End Type="Self.CCategory" Multiplicity="0..1*">
          <OnDelete Action="Cascade" />
       </End>
    </End>
</Association>

Example of SSDL is shown below:

<Association Name="CProductCategory">
    <End Role="PRODUCT" Type=Self.Store.CProduct" Multiplicity="0..1" >
       <OnDelete Action="Cascade" />
    </End>
</Association>

As you can see to add cascade deleting just define the following construction in CSDL or SSDL part of your .edmx file:

 <OnDelete Action="Cascade"/>

4. How can I get the default value of a database field in my Entity Framework project?

Issue:

I have a varchar2 “MyProperty” column in my Oracle database containing the default value. How can I get this value, e.g, to populate my Textbox in the user input form?

Solution:

You need to query MetadataWorkspace, for example, in the following way:

MetadataWorkspace workspace = context.MetadataWorkspace;
object value = new value();
var item = workspace.GetItems<EntityType>(DataSpace.CSpace).Where
 (i => i.Name == "MyEntity").Single();
value = item.Properties.Where
 (p => p.Name == "MyProperty").Single().DefaultValue;

We hope this material will be useful for you. Please provide your feedbacks and suggestions in comments to article.

2 Responses to “Entity Framework: Tips and Tricks, part 3”

  1. Sebastian Says:

    If I add the setting “TransactionScopeLocal=true” to my connection string as suggested in the note at the end of question #1 I get an exception telling me that the connection string parameter is not supported. Is this parameter really implemented in the current version?

  2. Devart Says:

    Thank you for the comment. We have made a correction, the parameter name should be “Transaction Scope Local”. This functionality is available since the latest 6.0.46 Beta build of dotConnect for Oracle.