Reputation: 159
Lets say i have 2 classes ( one from them comes from my entity framework and the other is global and its available in the entire application while EF one isnt) They both have the same properties and fields. Is there a easier and faster way to cast the Entity class to the global class other than that example?
Global one:
public class CompanyOwner
{
public Guid OwnerId { get; set; }
public string CompanyName { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
}
Entity model class
public class dbOwner
{
public Guid OwnerId { get; set; }
public string CompanyName { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
}
The way im doing it right now:
CompanyOwner owner = new CompanyOwner();
Owner dbOwner = entities.FirstOrDefault(.....)// some LINQ
owner.CompanyName = dbOwner.CompanyName;
owner.Address = dbOwner.Address;
owner.Email = dbOwner.Email;
owner.Phone = dbOwner.Phone;
Upvotes: 0
Views: 4116
Reputation: 47
It is the only way to cast or else you can create two different objects of the same class. However, I preferred to create a global class. It also is useful at the time of fetching the data from two different tables at that time we have to simply add the fields in the global class.
Upvotes: -1
Reputation: 2709
Since there are many tiny edge-cases and special features of interest in a mapping like this, you are probably well advised to use a library such AutoMapper as recommended by gsharp.
However, in order to give you some understanding of how one would build such a mapper, here is a very simple one. This finds all properties of the target type with a name which matches a property on the source type (case-invariant), and then generates a compiled delegate which instantiates a new instance of the target type (using default-constructor in this case) and then initializes the properties using values from a source instance.
This is the absolute most basic form, but should give you an idea of how a mapper works. Then you extend it by analyzing all constructors and finding an appropriate one (to support immutable types); you perform type casting operations when property types do not match; you add the ability to recognize name matches even when naming conventions differ (my_property
~ MyProperty
~ myProperty
); and the list goes on.
Implemention:
Func<TSource, TTarget> CreateMapper<TSource, TTarget>()
where TTarget : new()
{
var sourceProperties = typeof(TSource)
.GetProperties()
.Where(x => x.CanRead);
var targetProperties = typeof(TTarget)
.GetProperties()
.Where(x => x.CanWrite)
.ToDictionary(x => x.Name, x => x, StringComparer.OrdinalIgnoreCase);
var source = Expression.Parameter(typeof(TSource), "source");
var target = Expression.Variable(typeof(TTarget));
var allocate = Expression.New(typeof(TTarget));
var assignTarget = Expression.Assign(target, allocate);
var statements = new List<Expression>();
statements.Add(assignTarget);
foreach (var sourceProperty in sourceProperties)
{
PropertyInfo targetProperty;
if (targetProperties.TryGetValue(sourceProperty.Name, out targetProperty))
{
var assignProperty = Expression.Assign(
Expression.Property(target, targetProperty),
Expression.Property(source, sourceProperty));
statements.Add(assignProperty);
}
}
statements.Add(target);
var body = Expression.Block(new[] { target }, statements);
return Expression.Lambda<Func<TSource, TTarget>>(body, source).Compile();
}
Usage:
var mapper = CreateMapper<dbOwner, CompanyOwner>();
var source = new dbOwner
{
OwnerId = Guid.NewGuid(),
CompanyName = "My Name",
Address = "My Address",
Phone = "My Phone",
Email = "My Email"
};
var mapped = mapper(source);
Upvotes: 6
Reputation: 27937
AutoMapper is your friend here.
From the Homepage
AutoMapper is an object-object mapper. Object-object mapping works by transforming an input object of one type into an output object of a different type. What makes AutoMapper interesting is that it provides some interesting conventions to take the dirty work out of figuring out how to map type A to type B. As long as type B follows AutoMapper's established convention, almost zero configuration is needed to map two types.
Upvotes: 5