April, 2008

  • Wriju's BLOG

    LINQ to SQL : FAQ Answer By Matt Warren

    • 3 Comments

    Wonderful composition of FAQ is available at http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2769747&SiteID=1 by Matt Warren.

     

    Q: How do I get default values from the database when inserting new entities?

    A: LINQ to SQL does not support using default values from the database.  The values in the entity at the time SubmitChanges is called are used instead.  You can override how LINQ to SQL inserts entities by implementing an insert method on the DataContext.  For an entity type called ‘Entity’ implement a function with the signature of ‘InsertEntity(Entity instance)’. 

    Q:  How do I attach and update entities?  When I attach and call SubmitChanges nothing happens.

    A:  Attaching entities to a DataContext may not work as you intend.  An attached entity is merely the equivalent of an entity that has just been queried from the database and not yet modified.  In order to instruct the DataContext that you intend to have the entity updated you must provide it with information describing how the entity has changed.  You can do this in a variety of ways.  1) You can call Attach to add the entity to the DataContext and then modify individual properties.  This assumes the entity is not already in a modified state.  2) You can call the form of Attach that takes both a current and original instance of the entity.  The DataContext will recognize that individual properties values differ.  3) You can call the form of Attach that takes an additional Boolean parameter set to true to indicate that the DataContext should treat the entity as all properties modified.  The option requires that the object have a version property.

     Q: How do I serialize entities using .Net Remoting?

    A: LINQ to SQL does not support serialization using .Net Remoting.  Key data types such as EntityRef and EntitySet are not serializable. 

    Q: How do I serialize entities using WCF (Windows Communication Foundation)?

    A: LINQ to SQL supports serialization as XML via WCF by generating WCF serialization attributes and special serialization specific logic during code-generation.  You can turn on this feature in the designer by setting serialization mode to ‘Unidirectional’.  Note this is not a general solution for serialization as unidirectional mode may be insufficient for many use cases.

    Q: How do I move entities between tiers in my multi-tier application?

    A:  While it is possible to use WCF serialization to move entities between tiers it may be insufficient for your application as it will not allow for round-tripping of changes.  Defining a custom data exchange contract as part of your web service API is a better all around solution.

     Q: Should I create a new DataContext in every business logic method?

    A: The DataContext conforms to the Unit of Work design pattern.  Unless you are moving data between physical tiers between each operation you should keep your DataContext alive for the duration of work.

    Q: Should I keep my DataContext in a static/global/shared variable?

    A: The DataContext is not thread safe and is not meant to be shared.  A DataContext is meant to be used for a single unit or work or at most  for multiple consecutive units of work.

    Q: Where should I put my business logic?  The system I’m currently developing uses static methods on the entities themselves for loading, saving and other operations.

    A: The DataContext conforms to the Unit of Work design pattern.  A work context must exist and be maintained separate from the entities themselves.  You should either place all your business logic as methods on the DataContext or devise a separate business context that encapsulates a DataContext instance.  You should not be using static methods.

    Q: Are LINQ to SQL entities Business Entities or Data Transfer Objects?  How do I build a business layer on top of LINQ to SQL?

    A: LINQ to SQL entities are both business entities and data transfer objects.  LINQ to SQL takes the place of your Data Access Layer and is the basis for your Business Layer.  You can add business logic directly to the DataContext or encapsulate the DataContext in your own business context.  The purpose for making a separate business context would be to restrict access to other DataContext methods.  If this is not an issue for you, putting all business logic methods on the DataContext is the best choice.

     Q: How can I keep entities cached beyond the lifetime of a single DataContext?  I want to keep a collection of entities in a cache so that all subsequent requests can read from this cache instead of going back to the database each time.

    A: It is possible to cache entities beyond the lifetime of a single DataContext.  However, it is dangerous to do this for entities with defer loaded properties as you are likely to get accesses back to the originating DataContext if these properties are ever navigated.  You are also likely to unintentionally retain all entities materialized via that same DataContext causing what may appear to be a memory leak.  To alleviate these problems you can either turn deferred loading off when first retrieving these entities or you can dispose the DataContext after the entities are fully loaded using an operation such as ToList or ToArray.

     Q: How can I re-attach an entity to a new DataContext?  When I try to do this I get an exception thrown.

    A: LINQ to SQL does not support re-attaching entities.  Entities are never actually detached from their originating DataContexts. The Attach methods are intended to be used with entity instances that are newly created after round-tripping data from another physical tier.  LINQ to SQL detects that an entity belongs to another DataContext if any deferred properties are still unloaded.  It is possible to trick the DataContext into accepting entities from another DataContext by either not having deferred properties, pre-loading all of them or turning deferred loading off on the originating DataContext.

     Q: How can I use globally cached entities to initialize the association properties of a new entity instance or to change an association property in order make an update?  When I try this I get strange behaviors like inserts I did not intend or exceptions thrown during SubmitChanges.

    A: LINQ to SQL does not support mixing and matching entities loaded from different DataContext instances together in the same object graph.  Trying to do so is generally a bad idea.  Most association properties are bi-directional, so assigning one to a property of another or adding one to a collection property changes state and references in both entities.  This means that globally cached entities are being modified potentially on multiple threads at the same time (when running as a service).  As a general rule of thumb, a single connected entity graph should only be associated to a single unit of work at a time.  Instead of using globally cached entities to assign association properties, use entities retrieved from the DataContext you are using to perform the insert or update, or assign values to the foreign key fields directly to avoid extra round-trips to the database server.

     

    Namoskar!!!

  • Wriju's BLOG

    MSDN Magazine Topics Online

    • 1 Comments

    • C# (566)

  • Wriju's BLOG

    LINQ to XML : Modifying XML document

    • 8 Comments

    You have XML document now you want to modify that XML file using LINQ to XML. It is as easy as you generally modify any database column value.

     

    Let us create a dummy XML stream,

     

    //Create dummy XML to work

    var root = new XElement("parent",

        from i in new int[] { 1, 2, 3, 4, 5, 6 }

        select new XElement("child",

            new XAttribute("number", i)));

     

    This will create XML like,

    <?xml version="1.0" encoding="utf-8"?>

    <parent>

      <child number="1" />

      <child number="2" />

      <child number="3" />

      <child number="4" />

      <child number="5" />

      <child number="6" />

    </parent>

     

    Let us play with this XML file,

     

    //Get the element (child3)

    XElement child3 = root.Descendants("child").First(

        el => (int)el.Attribute("number") == 3);

     

    //Add element before the child3

    child3.AddBeforeSelf(new XElement("child25"));

     

    //Add sub-element to the child3

    child3.Add(new XElement("grandchild"));

     

    //Add element after the child3

    child3.AddAfterSelf(new XElement("child35"));

     

    //Add attribute to the child3

    child3.Add(new XAttribute("attr", "something"));

     

    //Change the existing attribute

    child3.SetAttributeValue("number", 100);

     

    After all these activities you will get the following output,

     

    <?xml version="1.0" encoding="utf-8"?>

    <parent>

      <child number="1" />

      <child number="2" />

      <child25 />

      <child number="100" attr="something">

        <grandchild />

      </child>

      <child35 />

      <child number="4" />

      <child number="5" />

      <child number="6" />

    </parent>

     

    Highlighted part is the modified portion of your XML. You can also remove an element,

     

    child3.Remove();

     

    Namoskar!!!

  • Wriju's BLOG

    LINQ to XML : Changing connectionString in app.config

    • 12 Comments

    When you create data bind application using wizard in Windows Forms application and connection string gets added to you settings file. Now you may be interested in changing that connection string but problems,

    1)     The connection string in settings has an Application Scope so it is ReadOnly property. You modify and remove “ReadOnly” from .vb file but it gets refreshed whenever you try to add new or modify anything.

    2)     Things in Settings gets stored into <applicationName>.exe.config file.

     

    I took the challenge to alter the app.config file and save it again. During my try I found that LINQ to XML is the easiest way to alter with its powerful API. So the sample I have created does looks for the first <connectionString> in the <connectionStrings> section and then alters the connectionString attribute of <add element.

     

    Actually in app.config the section looks like,

    <connectionStrings>

        <add name="AppConfigChange.My.MySettings.Connstr"

            connectionString=

    "Data Source=wghosh2k3\sqlexpress;Initial Catalog=Northwind;Integrated Security=True"

            providerName="System.Data.SqlClient" />

     

    I am changing the highlighted part and saving it back to the same file.

     

    And the code looks like,

     

    Dim sNewConnStr As String = ""

     

    'Get the file info

    Dim config As System.Configuration.Configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)

     

    'Load the file info

    Dim xml = XElement.Load(config.FilePath)

     

    'Get the first config section (first connection string info)

    Dim connStrXML = xml.Descendants("connectionStrings").Elements().First()

     

    'Get the connection string value

    Dim connStr = connStrXML.Attribute("connectionString").Value

     

    'Create an array with ';'

    Dim arrConn() As String = connStr.Split(";")

     

    For i As Int16 = 0 To arrConn.Length - 1

        'Get the attribute and value splitted by "="

        Dim arrSubConn() As String = arrConn(i).Split("=")

        If (arrSubConn.Length = 2) Then

            Dim sConnAttr As String = ""

            Dim sConnValue As String = ""

            sConnAttr = arrSubConn(0)

            sConnValue = arrSubConn(1)

     

            'Change Database name

            If (sConnAttr = "Initial Catalog") Then

                'This is the place where you will be changing the database name

                sConnValue = "NewDBName"       

       End If

     

            'Generate newly altered connection string

            sNewConnStr += sConnAttr + "=" + sConnValue + ";"

        End If

    Next

     

    After doing everything you need to save it back to the same file,

     

    'Modify the existing connection string information

    connStrXML.SetAttributeValue("connectionString", sNewConnStr)

     

    'Saving config at the same place

    xml.Save(config.FilePath)

     

     

    Namoskar!!!

Page 1 of 1 (4 items)