2

I want to deep copy of my complex C# object having DataTable as property.It is throwing error as "Table SalesData does not belong to this DataSet."

Here is my C# object:

public class Foo
{
    public VehicleDetails VehicleDetails { get; set; }
    public VehicleCondition VehicleCondition { get; set; }

    public string Zipcode { get; set; }
    public string StateCode { get; set; }
    public DataTable SalesData { get; set; }
    public DataTable OtherDataTable { get; set; }
}

I have used following code to clone object:

  public static T CloneFullObject<T>(T i)
    {
        if (Object.ReferenceEquals(i, null)) return default(T);

        var x = new XmlSerializer(i.GetType());
        using (var m = new MemoryStream())
        {
            x.Serialize(m, i);
            m.Seek(0, SeekOrigin.Begin);
            return (T)x.Deserialize(m);
        }
    }

I am creating object as:

   Foo foo = new Foo();

   VehicleDetails vehicleDetail = new VehicleDetails();
   // Fill vehicleDetail object

    VehicleCondition vehicleCondition = new VehicleCondition ();
   // Fill vehicleCondition object
   foo.VehicleDetails = vehicleDetail;
   foo.VehicleCondition = vehicleCondition;

   DataTable salesData = getDataTable();
   salesData.TableName = "salesData";
   foo.SalesData = salesData;

   DataTable otherData = getDataTable();
   salesData.TableName = "otherData";
   foo.OtherDataTable = salesData;

Below code is throwing error as:

       System.InvalidOperationException: There was an error generating the XML document. ---> System.ArgumentException: Table salesData does not belong to this DataSet.

Foo clonefullObject = CloneFullObject(foo);

Please help if I am missing something before cloning object.

Note: both Datatable have value and it's not null.

Edit: class Foo have some complex properties like:

    private int _mileage;
    public void SetMileage(int mileage) { _mileage = mileage; }
    private int _expectedMileage;
    public void SetExpectedMileage(int mileage) { _expectedMileage =       mileage; }

    public int GetMileage(bool flag)
    {
        return (flag)
                   ? _mileage
                   : Math.Max(_mileage, _expectedMileage);
    }
i3havi
  • 35
  • 9
  • 1
    Why use mix of data tables and business objects? Create `Sales` object with properties corresponding to data table columns and use collection of these objects. – Sergey Berezovskiy Aug 06 '15 at 07:33
  • @SergeyBerezovskiy - I think that would be same while serializing Sales object because It has DataTable property. I have used template object for reference but actually it has so many fields and private fields and public methods too. – i3havi Aug 06 '15 at 08:09
  • if Sales object has DataTable property, then follow my previous advice – Sergey Berezovskiy Aug 06 '15 at 08:10

1 Answers1

1

When cloning/copying objects you can simply clone/copy them. Serializing is quite expensive overkill, especially when implemented without concern for performance (you can read more in this SE question).

However, serialization is not your real problem, copying DataTable with both structure and data is. And it appears that your problem is not really your problem, your approach to it is your problem. DataTable.Copy() does all of that.

So how to do it? Well, how about properly?

On of proper approaches would be to implement ICloneable interface. It is kind of clumsy as return type is object. By implementing it on sub classes you can chain it deeper. I used as for casting in sample, have in mind that it will not generate exception on type mismatch. (As usually you can read more on some old SE question). You might, or might not, want to generate exceptions on faulty state (null) of DataTables.

public class Foo : ICloneable
{
    //some fields....

    private int _Bar; //private field
    public void SetBar(int value) { _Bar = value; } //Field setter        

    public object Clone()
    {
        var result = new Foo()
        {
            _Bar = _Bar, // private members are accessible from their scope, even when object is different
            Zipcode = Zipcode,
            StateCode = StateCode,
            SalesData = SalesData== null ? null : SalesData.Copy(),
            OtherDataTable = OtherDataTable == null ? null : OtherDataTable.Copy(),
            VehicleDetails = VehicleDetails.Clone() as VehicleDetails,
            VehicleCondition = VehicleCondition.Clone() as VehicleCondition,
        };

        // alternatively you can call setter methods
        result.SetBar(_Bar);

        return result;

    }
}

Notes:

You should work on creating object in better style, for example using Factory or at least use Object Initializer or constructor.

@SergeyBerezovskiy made a valid point by suggesting data model classes instead of full data tables.

Community
  • 1
  • 1
PTwr
  • 1,225
  • 1
  • 11
  • 16
  • Thanks for your solution but I have other private fields and methods, too. I updated my Foo object. So what should I do for this type of properties ? – i3havi Aug 06 '15 at 08:18
  • @i3i_iavi Because Clone() method is in scope of Foo object it can freely access private members of other instances of Foo class. You can call both setter methods and fields itself, depending on your needs. I updated answer with sample for such cases. – PTwr Aug 06 '15 at 09:02
  • I think I found solution. Actually I am cloning Foo 10 to 12 times parallel via thread and I have used static method and static method is not thread safe. Does it so ? I made methods as non static and now I am not getting such error. – i3havi Aug 06 '15 at 11:37
  • @i3i_iavi Static method is as much thread unsafe as any other method. Unsafe part comes from shared memory. Reading (and returning new object) is thread safe, reading and writing is definitely unsafe. It seems you have broader problem with paralleling at hand, you probably want to make another question regarding it. (SE comunity prefers one problem per question) – PTwr Aug 06 '15 at 11:51