Question

I have generated few classes using to LINQ to SQL

one of them being "Customer"

Now I want to create a Customer object that is disconnected.

i.e. I can create the object keep it in session and then attach it back only if I want to. Not automatically. Hence only if I attach it - it should affect my context's SubmitChange() otherwise not.

Is this possible?

Also can I add this detached object to a collection of attached objects without affecting SubmitChanges() or on add will the detached object become attached again?

Was it helpful?

Solution

There's no "Detach" method, but it is possible with serialization:

Customer customerCopy;
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream())
{
    bf.Serialize(ms, customer);
    ms.Position = 0;
    customerCopy = (Customer)bf.Deserialize(ms);
}

Be aware that it's cumbersome to re-attach the object afterward. The Attach table method is finicky - you generally need a Version (timestamp type) column on the entity in order for it to work.

Note - I just reread your question and it sounds almost as though you simply want to construct the object. If so, constructing a new Customer via new Customer() will not create an attached entity. It only becomes attached after you invoke the InsertOnSubmit or Attach method on the table.

Also, you can freely add detached entities to a List<Customer> (or similar) containing attached entities - Linq to SQL does not care about this, an entity only becomes attached if it is dispensed by the DataContext itself or if you attach it using one of methods above.

OTHER TIPS

For Linq to Sql, only the DataContractSerializer is supported.

There's a more performant way to Detach(), and that's using the following base method:

public void Detach()
{
   GetType().GetMethod("Initialize", BindingFlags.Instance |         
      BindingFlags.NonPublic).Invoke(this, null);
}

This will call the Initialize() method which will 'reset' all the FK properties. The trick is that this method is only generated when Serialization has been turned on. There's a way to get around this, check here for more info

Vitaliy, Sorry I lost that blogpost. I do still have the code though.

public class EntityBase : IEntityBase
{
    /// <summary>
    /// Detaches the entity, so it can be added to another dataContext. It does this by setting
    /// all the FK properties to null/default.
    /// </summary>
    public void Detach()
    {
        // I modified the .tt file to generate the Initialize method by default. 
        // The call to OnCreated() is moved to the constructor.
        GetType().GetMethod("Initialize", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(this, null);
    }
}

And here's the call to Detach() from my adapter

public class OrderAdapter : IOrderAdapter
{
    public void Add(IOrder order)
    {
        try
        {
            using (var db = new ATPDataContext())
            {
                Order newOrder = (Order)order;
                newOrder.Detach(); // not required for insertion, but to keep references to Product 
                db.Orders.InsertOnSubmit(newOrder);
                db.SubmitChanges();
            }
        }
        catch (Exception ex)
        {                
        }
    }
 }

And in my .tt file

#region Construction
public <#=class1.Name#>()
{
    Initialize();

    <# if (class1.HasPrimaryKey) {#>
        OnCreated();
    <# } #>
}

private void Initialize()
{
<#        foreach(Association association in class1.Associations) { #>
        <#=association.Storage#> = <#
        if (association.IsMany) {
            #>new EntitySet<<#=association.Type.Name#>>(attach_<#=association.Member#>, detach_<#=association.Member#>);
<#          } else {
            #>default(EntityRef<<#=association.Type.Name#>>); 
<#          }
    }
#>
    }
#endregion

HTH!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top