SkinnyPete63
SkinnyPete63

Reputation: 653

Entity Framework - insert record of one class into another "identical" object

Using database first entity framework. Inserting records into one of my tables, no problem at all. Then I discovered under certain, very rare, circumstances, I was getting duplicate records, which are actually ok. So my plan to deal with those was to create an identical table, catch the exception, put the duplicate in the identical table and examine it at some later stage.

However, I naively thought as they were identical tables, I could just insert the object I have already created into the other "error" table, which obviously I can't do ("cannot convert from 'original_class' to 'new_class'"), which I understand.

So is there a better way to do what I am trying to achieve, or is there a simple way to convert my 'original_class' to my 'new_class' as they are absolutely identical?

***Edit Thought it may be beneficial to add some code for clarity (not my actual code, just a representation of what I am trying to achieve)

My Transaction Class

public partial class Tran
{
    public string tranDescription
}

My Transaction Error Class

public partial class TranError
{
    public string tranDescription
}

How I am trying to process the error

using(var db = new tranEntities())
{
    Tran t = new Tran();
    t.tranDescription = @"Some Description";
    try
    {
        db.Trans.Add(t);
    }
    catch (System.Data.Entity.Infrastructure.DbUpdateException)
    {
        db.TransError.Add(t);
    }
}

I just typed that on the fly, so forgive any typos, I think you get the idea.

Upvotes: 0

Views: 337

Answers (3)

Steve Py
Steve Py

Reputation: 34653

An alternative to Tomislav's answer, if your project is using JSON you can switch identical types using JSON serialization:

public static class SwapperExtensions
{
    public static T2 Swap<T1,T2>(this T1 original) where T1:class where T2:class,new()
    {
        if (original == null)
            return null;

        try
        {
            var result = JsonConvert.SerializeObject(original);
            var newObject = JsonConvert.DeserializeObject<T2>(result);
            return newObject;
        }
        catch(Exception ex)
        {
            throw new ArgumentException("The provided types could not be swapped. See inner exception for details.", ex);
        }
    }
}

which then looks like:

var tran = new Tran { TranDescription = "Some description." };

// do stuff...

var tranError = tran.Swap<Tran, TranError>();

Obviously you would need to guard against exceptions when doing something like this if it's called with incompatible types. :)

Upvotes: 2

Tomislav Baljint
Tomislav Baljint

Reputation: 118

You could make a method that returns a new object as:

public ErrorObject ConvertToErrorObject(OriginalObject originalObject)
{
    var errorObject = new ErrorObject();
    errorObject.Property1 = originalObject.Property1;
    errorObject.Property2 = originalObject.Property2;

    return errorObject;
}

Then just save the error object as normal.

If this happens on multiple types you could make a generic method that uses reflection and goes through the OriginalObject properties, gets there values, and sets them on the ErrorObject properties with the same name.

Generic method (properties with the same names have to be of the same type):

    public static Tout CloneAndCast<Tin, Tout>(Tin source)
        where Tin : class
        where Tout : class, new()
    {
        if(source != null)
        {
            var clone = new Tout();

            IEnumerable<PropertyInfo> membersIn = typeof(Tin).GetProperties();
            PropertyInfo[] membersOut = typeof(Tout).GetProperties();

            foreach(PropertyInfo member in membersIn)
            {
                membersOut.FirstOrDefault(o => o.Name == member.Name)?.SetValue(clone, member.GetValue(source));
            }

            return clone;
        }
        else
        {
            return null;
        }
    }

Upvotes: 2

Stackberg
Stackberg

Reputation: 320

I think a decent way to do it would be to create a base class with all the properties

public class TranBaseClass {
     public string tranDescription
     // other properties
}

Then both Tran and TranError could inherit from those:

public partial class Tran : TranBaseClass {}

public partial class TranError : TranBaseClass {} 

Then I would create constructors for both Tran and TranError which would accept the base class as a parameter:

var tran = new Tran(TranBaseClass)
var tranError = new Tran(TranBaseClass)

And your code could be something like:

using(var db = new tranEntities())
{
    var t = new TranBaseClass();
    t.tranDescription = @"Some Description";
    try
    {
        db.Trans.Add(new Tran(t));
    }
    catch (System.Data.Entity.Infrastructure.DbUpdateException)
    {
        db.TransError.Add(new TranError(t));
    }
}

Upvotes: 1

Related Questions