0

In a Dapper ORM application, I want to assign one object to another, or all data members at once. Like this:

public class TableA
{
    public int    UserId   { get; set; }
    public string ClientId { get; set; }
    // ... more fields ...

    public bool Query()
    {
        bool Ok = false;
        try{
            // Method A
            TableA Rec = QueryResultRecords.First(); 
            MyCopyRec(Rec, this);                        // ugly

            // Method B
            this = QueryResultRecords.First();           // avoids CopyRec, does not work

            Ok = true;
        }
        catch(Exception e){
            Ok = false;
        }
        return Ok;
    }
}

With Method A you can assign the object from .First() directly to a new object of class TableA, and need a custom method MyCopyRec to get the data in the data members of the same class.

However, with Method B you cannot assign the same object directly to this.

Or is there another way to do this?

Roland
  • 4,619
  • 7
  • 49
  • 81
  • Why not just make the method static and return `TableA` from `Query`? Also it is considered bad design to put the data access methods inside the models those methods are retrieving. ["Separation of concerns"](https://en.wikipedia.org/wiki/Separation_of_concerns) tells us that `Query` should be in a separate class. – Scott Chamberlain Oct 28 '15 at 13:45
  • 1
    Maybe use AutoMapper? – Derreck Dean Oct 28 '15 at 13:50
  • @ScottChamberlain That is surely an option, but my sample code is simplified. My question is if there is a simple Method B to write a class method that leaves the query result directly in the class data members. – Roland Oct 28 '15 at 13:51
  • @DerreckDean Do you imply that there is no simple, builtin way in C# to do something like MethodB, and that that is the reason the AutoMapper tool is created? – Roland Oct 28 '15 at 13:53
  • No, there's no way to copy all properties from one object to another that is **built-in** to .Net. You can write an extension that uses reflection to loop through and copy properties, which is basically what AutoMapper does. However, this begs the question: Does your object *really* have that many properties where it's a pain to write `target.Property = source.Property` for them? The overhead for reflection is much more than just putting your nose to the grindstone and typing up assignments. My $0.02. – Derreck Dean Oct 28 '15 at 13:56
  • @DerreckDean Yes, I wanted to create such classes for the tons of tables in our database, and several classes have lots and lots of columns. Tables with 30 - 60 columns are usual here. So to me it looks like unfortunate that there is no builtin way for copying all properties at once. My nose would not survive the grindstone. I could of course write code that reads the table with all column definitions and generates the boring code for me . . . – Roland Oct 28 '15 at 14:04
  • @ScottChamberlain Bad design: In some (most) cases you are of course right, but in other cases the query really belongs to the table. I don't want to be forced to create a second class just because I cannot figure out how to do MethodB, but if it turns out to be impossible, I'll curse to C#, then just do it. – Roland Oct 28 '15 at 14:10
  • I did mention earlier that you could write an extension method to do the work for you. – Derreck Dean Oct 28 '15 at 20:39

2 Answers2

1

You cannot assign a object to "this" if "this" is a reference type, e.g. a class. "this" is a pointer to the current class instance. This would only work if this is a value type, e.g. a struct.

You can only assign values to properties of "this" (which is what probably happens in the (CopyRec method), like:

var result = QueryResultRecords.First();
this.UserId  = result.UserId;
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
K.J.
  • 230
  • 1
  • 8
  • You must be right, but I was thinking of my Class as a struct. Of course a class can have data members AND methods, but assigning something to a method has no meaning. So it is too bad I cannot assign the DATA values of an object to `this`. Is this a missing feature of C#, for which DataMapper is a repair? – Roland Oct 28 '15 at 13:59
0
/// <summary>
/// Extension for 'Object' that copies the properties to a destination object.
/// </summary>
/// <param name="source">The source.</param>
/// <param name="destination">The destination.</param>
public static void CopyProperties(this object source, object destination)
{
    // If any this null throw an exception
    if (source == null || destination == null)
        throw new ArgumentException("Source or/and Destination Objects are null");
    // Getting the Types of the objects
    Type typeDest = destination.GetType();
    Type typeSrc = source.GetType();

    // Iterate the Properties of the source instance and  
    // populate them from their desination counterparts  
    PropertyInfo[] srcProps = typeSrc.GetProperties();
    foreach (PropertyInfo srcProp in srcProps)
    {
        if (!srcProp.CanRead)
        {
            continue;
        }
        PropertyInfo targetProperty = typeDest.GetProperty(srcProp.Name);
        if (targetProperty == null)
        {
            continue;
        }
        if (!targetProperty.CanWrite)
        {
            continue;
        }
        if ((targetProperty.GetSetMethod().Attributes & MethodAttributes.Static) != 0)
        {
            continue;
        }
        if (!targetProperty.PropertyType.IsAssignableFrom(srcProp.PropertyType))
        {
            continue;
        }
        // Passed all tests, lets set the value
        targetProperty.SetValue(destination, srcProp.GetValue(source, null), null);
    }
}

Here's that method I talked about in the comments above.

Also refer to this link: Apply properties values from one object to another of the same type automatically?

Community
  • 1
  • 1
Derreck Dean
  • 3,708
  • 1
  • 26
  • 45
  • Thank you for your code sample, I will surely study it. For now, I am convinced that C# is missing a feature of assigning to `this`, and it is more like the spirit of C# to go with a kind of separate Service class like in http://stackoverflow.com/a/18285160/1845672 which is the reason I accepted the other answer here. – Roland Oct 29 '15 at 09:23