Converting list of one class to list of another class? - c#

I am calling a stored procedure from Entity Framework and trying to get result of stored procedure in a model-view class but I am getting error while casting list of Result class I got from entity framework -
Below code I tried, but I am getting error while trying to cast, I tried other way also like ConvertAll<> but didn't work -
public List<DepartmentModelView> GetDepartmentData()
{
using (Model1Container obj = new Model1Container())
{
return obj.usp_getDepartment().ToList<usp_getDepartment_Result>().Cast<DepartmentModelView>.ToList();
}
}
This is the auto generated result class in Model.tt
namespace MvcApplication4.Models
{
using System;
public partial class usp_getDepartment_Result
{
public Nullable<int> Depid { get; set; }
public string DepName { get; set; }
}
}
But I want it to be returned in DepartmentModelView class-
public class DepartmentModelView
{
public Nullable<int> Depid { get; set; }
public string DepName { get; set; }
}
Please suggest how could I do this ?

If the rest of your Code works, you can use the Linq-Select-Projection:
public List<DepartmentModelView> GetDepartmentData()
{
using (Model1Container obj = new Model1Container())
{
return obj.usp_getDepartment().ToList<usp_getDepartment_Result>().Select(m=>new DepartmentModelView{Depid=m.Depid, DepName=m.DepName}).ToList();
}
}

You could implement implicit cast in another partial file for usp_getDepartment_Result:
namespace MvcApplication4.Models
{
public partial class usp_getDepartment_Result
{
static public implicit operator DepartmentModelView(usp_getDepartment_Result input)
{
return new DepartmentModelView
{
Depid = input.Depid,
DepName = input.DepName
};
}
}
}
Then your existing code ought to work.

Use AutoMapper (from Nuget). You can create a map from one class to another and you can do all kinds of manipulation during the mapping operation for cases where it isn't a straightforward copy of properties like this one.
And for simple cases like this one, Automapper will autowire up the conversion when it finds properties with the same names and types.

Related

How add dynamically a list form one object to another?

I have a class that contains a list. I want to copy that list to another object that contains the same type and amount of attributes.
List<CinemaUnitSchema> cinemaUnitSchemas = new List<CinemaUnitSchema>();
foreach (CinemaUnit cinemaUnits in scenario.CinemaUnits)
{
cinemaUnitSchemas.Add(new CinemaUnitSchema
{
Name = cinemaUnits.Name,
AttendantPoints = cinemaUnits.AttendantPoints,
ShowPoints = cinemaUnits.ShowPoints
});
}
scenarioSchema.CinemaUnits.AddRange(CinemaUnitSchemas);
However, I'm receiving an error in this line of code;
AttendantPoints = cinemaUnits.AttendantPoints
The error I'm receiving is:
"Cannot implicitly convert type 'System.Collections.Generic.List < MyApp.Models.AttendantPoint >' to 'System.Collections.Generic.List < MyApp.Schemas.AttendantPointSchema >'."
Class of CinemaUnit is:
public class CinemaUnit
{
public string Name { get; set; }
public List<AttendantPoint> AttendantPoints { get; set; }
public bool ShowPoints { get; set; }
}
The Class of CinemaUnitSchema is:
public class CinemaUnitSchema
{
public string Name { get; set; }
public List<AttendantPoint> AttendantPoints { get; set; }
public bool ShowPoints { get; set; }
}
Solution Intended
Add in each iteration the respective list to the new object.
Thanks,
You can write a Copy method that makes a shallow copy using reflection.
void Copy(object from, object to)
{
var dict = to.GetType().GetProperties().ToDictionary(p => p.Name, p => p);
foreach(var p in from.GetType().GetProperties())
{
dict[p.Name].SetValue(to, p.GetValue(from,null), null);
}
}
What you actually need it's a way to convert AttendantPoint to AttendantPointSchema.
Solution 1: You can use AutoMapper framework to do it.
Solution 2: You can write generic converter like #Eser suggested.
Solution 3: You can crate converter manually for each class using extension methods, implicit or explicit operators or just write helper class with static functions.
Not sure if this is the problem, but it is probably a good bet that it is.
You are using a foreach statement with the camel case cinemaUnits but when you are trying to copy the fields you are using the title case CinemaUnits instead of the variable with camel case.

I want to fill class members with default if they are missing, using generic in C#

I have multiple web requests that post JSON object and I have serializable classes with all the fields. For example:
[Serializable]
public class RequestOne()
{
public string date;
public string information;
public string subject;
}
[Serializable]
public class RequestTwo()
{
public int ID;
public string Data;
public string message;
}
And my method takes partially filled request class and I want to fill in any missing fields with default values declared in constant class.
And I want to avoid writing each method with for each request, like :
public static void FillWithDefault(this RequestOne request)
{ if (request.date.Equals(null)) request.date = DEFAULT_DATE;
if (request.information.Equals(null)) request.information = DEFAULT_INFO;
if (request.subject.Equals(null)) request.subject = DEFAULT_SUBJECT;
}
public static void FillWithDefault(this RequestTwo request)
{
//do the same for the fields in RequestTwo
}
I want to know if there is any way to achieve this using generic?
I want to do something similar to this:
public static void FillWithDefault<T>(this T request)
{
if(typeof(T) == typeof(request))
{
//check each member in request and fill with default if it's null
}
.
.
.
}
So that in my main method I can use like this :
RequestOne request = new RequestOne();
request.FillWithDefault();
RequestTwo request2 = new RequestTwo();
request2.FillWithDefault();
Can someone please help with idea on this? Am I overthinking on this? I'm new to generic so please feel free to advise on my code.
Edit
Sorry guys, I did not mention that I will be using this method for test automation. Those request contracts cannot be changed since it's by design. Sorry again for the confusion!
Use constructors. Also make use of properties. Don't gather the default filling code to one place, it's the responsibility of the classes so keep them there.
[Serializable]
public class RequestOne()
{
public string date { get; set; };
public string information { get; set; };
public string subject { get; set; };
public RequestOne()
{
Date = DEFAULT_DATE;
Information = DEFAULT_DATE;
Subject = DEFAULT_SUBJECT;
}
}
[Serializable]
public class RequestTwo()
{
public int ID { get; set; };
public string Data { get; set; };
public string Message { get; set; };
public RequestTwo()
{
Data = DEFAULT_DATA;
message = DEFAULT_MESSAGE;
}
}
Generics are used when the types have common operations/properties defined so you can apply the same routine for each type in one place instead of declaring different methods for each type.
However in this case, you have two different types with different properties, so I would not use generics here. You can achieve it with manual type checking and using reflection to get properties and set them but it's not a good way and definitely wouldn't be a good usage of generics.
Overloading is the way to go.
you can use property
[Serializable]
public class RequestOne()
{
private string _date;
public string date { get { return _date;} set { _date = value ?? DEFAULT_DATE; }};
public string information; // same here
public string subject; //same here
}

Cannot implicitly convert type System.Collections.Generic.List

Exception: Cannot implicitly convert type 'System.Collections.Generic.List<ModelClass>' to
'System.Collections.Generic.List<ModelClass>'
I can't figure out what mistake I have made. This is the structure what I am following:-
namespace XMailerData.DAL
{
public class Data : IData, IDisposable
{
XmailerEntities context = new XmailerEntities();
public List<PageContentModel> GetPageContent()
{
List<PageContentModel> lPageContent = (from pc in context.T_PageContent
select new PageContentModel
{
contentId = pc.ContentId,
description = pc.Description
}).AsEnumerable().ToList();
return lPageContent;
}
}
}
In above class I am trying to return a List that contain result generated from linq expression
and PageContentModel is defined in same namespace but with different class name.
namespace XMailerData.CompositeModel
{
public class PageContentModel
{
public int pageId { get; set; }
public int contentId { get; set; }
public string description { get; set; }
}
}
Now, in my another class library named Classes I trying to call out that function as mentioned below
namespace Classes.Helper
{
public class DAL
{
public static List<PageContentModel> FetchPageContent()
{
IData iData;
List<PageContentModel> lPageContent = new List<PageContentModel>();
lPageContent = iData.GetPageContent(); // Here i'm getting an error
return lPageContent;
}
}
}
Here I am trying to bind the result from iData.GetPageContent() to another list that is defined in another class but I am failing to do so.
namespace Classes.CompositeModel
{
public class PageContentModel
{
public int pageId { get; set; }
public int contentId { get; set; }
public string description { get; set; }
}
}
Of all my tries I am not able to resolve following error:-
Exception: Cannot implicitly convert type
'System.Collections.Generic.List<XMailerData.CompositeModel.PageContentModel>'
to
'System.Collections.Generic.List<Classes.CompositeModel.PageContentModel>'
Can someone help me to overcome this problem and acknowledge me what mistake I have made because of which I got such type of error.
Conclusion:
Thanks for the insight it was really helpful. Now I have modified my code, it's now working properly. Here's what i have done now.
namespace Classes.Helper
{
public class DAL
{
public static List<PageContent> FetchPageContent()
{
IData iData = new Data();
List<PageContent> lPageContent = new List<PageContent>();
lPageContent = iData.GetPageContent()
.Select(pc => new PageContent
{
pageId = pc.pageId,
contentId = pc.contentId,
description = pc.description,
}).ToList();
return lPageContent;
}
}
}
To avoid ambiguity I have renamed the property class from PageContentModel to PageContent. Thanks Reza Aghaei, Monroe Thomas and Nikita for sharing suggestion. Both Reza Aghaei, Monroe Thomas are acceptable but it won't be possible to accept two answer so I'm accepting one answer and upvoting rest.
XMailerData.CompositeModel.PageContentModel and Classes.CompositeModel.PageContentModel has same properties,but they resides in different namespaces, that makes them two different classes.
So, the class Data should refer Classes.CompositeModel.PageContentModel and not XMailerData.CompositeModel.PageContentModel.
If you can't change the code to share the same PageContentModel class type, you can also try something like the following to convert an instance of one type to another if the properties are compatible:
lPageContent = iData.GetPageContent()
.Select(content => new Classes.CompositeModel.PageContentModel
{
pageId = content.pageId,
contentId = content.contentId,
description = content.description
})
.ToList();
The error is self describing:
Cannot implicitly convert type
'System.Collections.Generic.List<XMailerData.CompositeModel.PageContentModel>'
to 'System.Collections.Generic.List<Classes.CompositeModel.PageContentModel>'
Take a look at Namespaces.
Even though these two class have the same name and same properties, while they are in different namespaces, they can't be converted to each other implicitly.
lPageContent = iData.GetPageContent(); // Here i'm getting an error
Here you are putting result of your GetPageContent method which its type is List<XMailerData.CompositeModel.PageContentModel> to lPageContent which its type is List<Classes.CompositeModel.PageContentModel>
You can fix the problem this way (which also Monroe Thomas mentioned in his good answer)
namespace Classes.Helper
{
public class DAL
{
public static List<Classes.CompositeModel.PageContentModel> FetchPageContent()
{
IData iData= new Data();
lPageContent = iData.GetPageContent()
.Select(x=>
new Classes.CompositeModel.PageContentModel()
{
pageId = x.pageId,
contentId = x.contentId,
description = x.description
}).ToList();
return lPageContent;
}
}
}

Using a Variable as List Type in C#

I am currently using a list to handle a JSON string which works fine for one instance of this, as can be seen below. What I want to do is make these methods that handle the conversion completely generic so I can use them for multiple JSON strings.
This is a snippet of my current code as it stands.
public class GetPerson
{
public string fooName { get; set; }
public string fooAddress { get; set; }
public string fooPosition { get; set; }
}
public class GetPosition
{
public string fooTitle { get; set; }
public string fooDepartment { get; set; }
public string fooSalary { get; set; }
}
private static List<GetPerson> ConvertToList(string jsonString)
{
List< listJson = new List<JsonObject>();
listJson = (List<GetPerson>)JsonConvert.DeserializeObject<List<GetPerson>>(jsonString);
return listJson;
}
This is just a quick sample but the List<GetPerson> is what I need to be generic so it can be reused, because as it stands the GetPosition will obviously not work with this, as I would want to be able to iterate through my code changing the type accordingly.
Is there a way I can assign a variable as a type? I saw another question about this but it didn't go into detail. Or is there another way that this could be achieved?
Thanks in advance.
Very Simple. You just have to make ConvertToList() generic and pass the desired class as Type Paramter in ConvertToList()
private static List<T> ConvertToList<T>(string jsonString)
{
var listJson = new List<JsonObject>();
listJson = (List<T>)JsonConvert.DeserializeObject<List<T>>(jsonString);
return listJson;
}
var personList = ConvertToList<GetPerson>(jsonString);
var positionList = ConvertToList<GetPosition>(jsonString);
You can use Generics to help make the ConvertToList function reusable for different types
private static List<T> ConvertToList<T>(string jsonString)
{
return (List<T>)JsonConverty.DeserializeObject<List<T>>(jsonString();
}
You can now call it using both GetPerson and GetPosition as the generic type.
var listOfPeople = ConvertToList<GetPerson>(personJson);
var listOfPositions = ConvertToList<GetPosition>(positionJson);
You can read more about Generics on MSDN.
Also, if all that you want to do is to [de]serialize JSON, you might want to consider a third-party library for that like JSON.net, Jil or ServiceStack.Text, all of which have built in functions to do what you are trying to do.

Get collection property of a specific type

I have a class MyDatabaseContext that has a series of DbSet collection properties:
public DbSet<EntityA> EntitiesA { get; set; }
public DbSet<EntityB> EntitiesB { get; set; }
public DbSet<EntityC> EntitiesC { get; set; }
I need to get the name of the collection given the type of the entity.
For example, I have "EntityB" and want to get as a result "EntitiesB".
I really wanted to avoid switch-case statements, since MyDatabaseContext is generated automatically (T4 templates).
if you just want the name of the property here you go. I would just refine the answer given by hunter. You can use the same method with string as return type.
public string GetEntitiName<T>() where T : class
{
PropertyInfo propInfo = typeof(MyDatabaseContext).GetProperties().Where(p => p.PropertyType == typeof(DbSet<T>)).FirstOrDefault();
string propertyName = propInfo.Name; //The string has the property name ..
return propertyName;
}
I tried a sample similar to your situation. Try replacing List with DbSet.
class Program
{
public static void GetEntities<T>() where T : class
{
var info = typeof(TestClass1).GetProperties().Where(p => p.PropertyType == typeof(List<T>));
Console.WriteLine(info.FirstOrDefault().Name);
}
static void Main(string[] args)
{
GetEntities<int>();
Console.ReadLine();
}
}
public class TestClass1
{
public List<int> IntTest { get; set; }
public List<double> DoubleTest { get; set; }
public List<string> IStringTest { get; set; }
}
This sample works.
I know this is old page, But my answer maybe useful for other guys referring here. (like me)
I think you want to accessing EntitiesB to run a query on it, like EntitiesB.Where(a=>a.bla=="blabla"). If I'm right or another visitor of this page needs something like this, just easily use the following code:
using System.Data.Entity.Infrastructure;
using System.Data.Objects;
((IObjectContextAdapter)_dbContext).ObjectContext.CreateObjectSet<EntityB>()
Description:
_dbContext is Context class inherting from DbContext.
EntitiesB is DbSet<EntityB> defined in Context class.
Example:
Ilist result = ((IObjectContextAdapter)_dbContext).ObjectContext.CreateObjectSet<EntityB>().Where(b=>b.bla=="blabla").ToList();
Your generated file is a partial class, you could create a new file and declare a class with same name using the keyword partial, then make a method which will return the desired Collection...
I haven't actually done this myself, but it sounds like what you want to do is to use reflection to locate the property of type "DbSet" that has the appropriate generic type parameter. The following pseudo-C# should get you started:
foreach ( FieldInfo field in this.GetType() )
{
if ( field.FieldType.IsGenericType )
{
foreach ( Type param in field.FieldType.GetGenericArguments() )
{
if ( param.Name == soughtType )
{
return field.Name;
}
}
}
}

Categories