EF Data setting ViewModel - c#

I have a ViewModel where objects are all string and the model from the database Address is a list. I wanted to know if there is any other way to set the viewModel string values other then the way I have it done below? Any advice on how I can combine the two ListOfProducts.Select lines?
static void Main(string[] args)
{
//EF Data
List<Address> ListOfProducts = new List<Address>();
ListOfProducts.Add(new Address() { StreetLine1="address 1",StreetLine2="address line2 1" });
ViewModelAddress vm = new ViewModelAddress();
vm.StreetLine1 = ListOfProducts.Select(a => a.StreetLine1).FirstOrDefault();
vm.StreetLine2 = ListOfProducts.Select(a => a.StreetLine2).FirstOrDefault();
}
class Address
{
public string StreetLine1 { get; set; }
public string StreetLine2{ get; set; }
}
class ViewModelAddress
{
public string StreetLine1 { get; set; }
public string StreetLine2 { get; set; }
}

var vm = ListOfProducts.Select(a => new ViewModelAddress
{StreetLine1 = a.StreetLine1, StreetLine2 = a.StreetLine2}).FirstOrDefault();

Related

C# Bad Performance OData when using extension

I have a Web API for OData services. I have a lot of table with many relations. Here is some of the table:
MSADDRESSCOUNTRY
public partial class MSADDRESSCOUNTRY
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage","CA2214:DoNotCallOverridableMethodsInConstructors")]
public MSADDRESSCOUNTRY()
{
this.MSADDRESSPROVINCEs = new HashSet<MSADDRESSPROVINCE>();
}
public int ID { get; set; }
public string CODE { get; set; }
public string COUNTRYNAME { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage","CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<MSADDRESSPROVINCE> MSADDRESSPROVINCEs { get; set; }
}
MSADDRESSPROVINCE
public partial class MSADDRESSPROVINCE
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public MSADDRESSPROVINCE()
{
this.MSADDRESSDISTRICTs = new HashSet<MSADDRESSDISTRICT>();
}
public int ID { get; set; }
public Nullable<int> COUNTRYID { get; set; }
public string PROVINCENAME { get; set; }
public virtual MSADDRESSCOUNTRY MSADDRESSCOUNTRY { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage","CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<MSADDRESSDISTRICT> MSADDRESSDISTRICTs { get; set; }
}
MSADDRESSDISTRICT
public partial class MSADDRESSDISTRICT
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public MSADDRESSDISTRICT()
{
this.MSADDRESSSUBDISTRICTs = new HashSet<MSADDRESSSUBDISTRICT>();
}
public int ID { get; set; }
public Nullable<int> PROVINCEID { get; set; }
public string DISTRICTNAME { get; set; }
public virtual MSADDRESSPROVINCE MSADDRESSPROVINCE { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<MSADDRESSSUBDISTRICT> MSADDRESSSUBDISTRICTs { get; set; }
}
I create DTO object model for every table with the property is the same with Database object model.
I want the client can use $expand keyword to get child data and/or parent data.
For MSADDRESSCOUNTRY I need to write the code like this.
[EnableQuery(MaxExpansionDepth = 4)]
public IQueryable<MsAddressCountryObject> Get()
{
return db.MSADDRESSCOUNTRies.Select(c => new MsAddressCountryObject
{
ID = c.ID,
CODE = c.CODE,
COUNTRYNAME = c.COUNTRYNAME,
MSADDRESSPROVINCEs = c.MSADDRESSPROVINCEs.Select(data => new MsAddressProvinceObject()
{
ID = data.ID,
COUNTRYID = data.COUNTRYID,
PROVINCENAME = data.PROVINCENAME,
MSADDRESSCOUNTRY = new MsAddressCountryObject()
{
ID = data.MSADDRESSCOUNTRY.ID,
CODE = data.MSADDRESSCOUNTRY.CODE,
COUNTRYNAME = data.MSADDRESSCOUNTRY.COUNTRYNAME,
},
MSADDRESSDISTRICTs = data.MSADDRESSDISTRICTs.Select(dist => new MsAddressDistrictObject()
{
ID = dist.ID,
PROVINCEID = dist.PROVINCEID,
DISTRICTNAME = dist.DISTRICTNAME,
})
})
});
}
For MSADDRESSPROVINCE I need to write the code like this.
[EnableQuery(MaxExpansionDepth = 4)]
public IQueryable<MsAddressProvinceObject> Get()
{
return db.MSADDRESSPROVINCEs.Select(data => new MsAddressProvinceObject()
{
ID = data.ID,
COUNTRYID = data.COUNTRYID,
PROVINCENAME = data.PROVINCENAME,
MSADDRESSCOUNTRY = new MsAddressCountryObject()
{
ID = data.MSADDRESSCOUNTRY.ID,
CODE = data.MSADDRESSCOUNTRY.CODE,
COUNTRYNAME = data.MSADDRESSCOUNTRY.COUNTRYNAME,
},
MSADDRESSDISTRICTs = data.MSADDRESSDISTRICTs.Select(dist => new MsAddressDistrictObject()
{
ID = dist.ID,
PROVINCEID = dist.PROVINCEID,
DISTRICTNAME = dist.DISTRICTNAME
})
});
}
That code works fast. But if I add/change/remove column, I have to modify the controller manually, one by one for all controller. For example, if I want to add geological coordinate in MSADDRESSDISTRICT, I have to change the code in Country Controller, Province Controller and District Controller.
So I decide to create extension method like this.
public static MsAddressCountryObject ToDTO(this MSADDRESSCOUNTRY data)
{
return new MsAddressCountryObject()
{
ID = data.ID,
CODE = data.CODE,
COUNTRYNAME = data.COUNTRYNAME,
};
}
public static IQueryable<MsAddressCountryObject ToDTO(this IEnumerable<MSADDRESSCOUNTRY datas)
{
return datas.Select(country =
{
var obj = country?.ToDTO();
obj.MSADDRESSPROVINCEs = country.MSADDRESSPROVINCEs?.ToDTO();
return obj;
}).AsQueryable();
}
public static MsAddressProvinceObject ToDTO(this MSADDRESSPROVINCE data)
{
return new MsAddressProvinceObject()
{
ID = data.ID,
COUNTRYID = data.COUNTRYID,
PROVINCENAME = data.PROVINCENAME,
MSADDRESSCOUNTRY = data.MSADDRESSCOUNTRY?.ToDTO()
};
}
public static IQueryable<MsAddressProvinceObject ToDTO(this IEnumerable<MSADDRESSPROVINCE datas)
{
return datas.Select(province =
{
var obj = province?.ToDTO();
obj.MSADDRESSDISTRICTs = province.MSADDRESSDISTRICTs.ToDTO();
return obj;
}).AsQueryable();
}
public static MsAddressDistrictObject ToDTO(this MSADDRESSDISTRICT data)
{
return new MsAddressDistrictObject()
{
ID = data.ID,
PROVINCEID = data.PROVINCEID,
DISTRICTNAME = data.DISTRICTNAME,
MSADDRESSPROVINCE = data.MSADDRESSPROVINCE?.ToDTO()
};
}
public static IQueryable<MsAddressDistrictObject ToDTO(this IEnumerable<MSADDRESSDISTRICT datas)
{
return datas.Select(district =
{
var obj = district?.ToDTO();
obj.MSADDRESSSUBDISTRICTs = district.MSADDRESSSUBDISTRICTs?.ToDTO();
return obj;
}).AsQueryable();
}
And the controller just like this.
[EnableQuery(MaxExpansionDepth = 4)]
public IQueryable<MsAddressCountryObject Get()
{
return db.MSADDRESSCOUNTRies.ToDTO()
}
And that makes the performance really bad. I think the extension is making a lot of memory allocation or some thing that make the result not being delivered directly to the client.
My goal is to create the code easy to maintain, and the performance not drop significantly.
I have many relation in other table. I want the $expand works without write all parent/child Select statement manually and one by one.
I have try to not calling ToDTO() from all the extension method. The result is the performance is fast. But I lost all the relation or I need to write the parent/child Select statement for all method.
Any suggestion will help.
Thanks.

Adding data from one list to another using linq

I need to populate a dropdown in my UI and hence added List object to the view model in my c# application. I am fetching the data in my controller code for the dropdown. What's the best way to assign data to the viewmodel object. Is linq an option?
I basically need to assign fundclasses to fundTrackRecord.FundClass
The main Viewmodel:
public class FundPerformanceVM
{
public FundPerformanceVM()
{
TrackRecord = new List<TrackRecordVM>();
}
public int FundId { get; set; }
public string FundName { get; set; }
public List<FundClassVM> FundClass { get; set; }
public string BenchmarkName1 { get; set; }
public string BenchmarkName2 { get; set; }
public List<TrackRecordVM> TrackRecord { get; set; }
public List<Tuple<string, string, string>> FundStatistics { get; set; }
}
public class FundClassVM
{
public int FundClassId { get; set; }
public string FundClass { get; set; }
}
Controller code:
var service = GetViewService<V_LEGAL_FUND_CLASS_SUMMARY>();
foreach (KeyValuePair<int, IEnumerable<FUND_PERFORMANCE>> entry in allPerformance)
{
var fundClasses = service.GetAll().Where(x => x.FUND_ID == entry.Key).Select(x => new { x.LEGAL_FUND_CLASS_ID, x.LEGAL_FUND_CLASS}).ToList();
var fundTrackRecord = new FundPerformanceVM();
fundTrackRecord.FundClass = ??;
If I understood correctly the structure of your model, you can try this:
fundTrackRecord.FundClass = fundClasses.Select(fc => new FundClassVM
{
FundClassId = fc.LEGAL_FUND_CLASS_ID,
FundClass = fc.LEGAL_FUND_CLASS
}).ToList();
You can also do this directly, replacing the code:
var fundClasses = service.GetAll().Where(x => x.FUND_ID == entry.Key).Select(x => new { x.LEGAL_FUND_CLASS_ID, x.LEGAL_FUND_CLASS}).ToList();
var fundTrackRecord = new FundPerformanceVM();
With:
var fundTrackRecord = new FundPerformanceVM();
fundTrackRecord.FundClass = service.GetAll().
Where(x => x.FUND_ID == entry.Key).
Select(fc => new FundClassVM
{
FundClassId = fc.LEGAL_FUND_CLASS_ID,
FundClass = fc.LEGAL_FUND_CLASS
}).ToList();

C# nested properties

I have a model like this that includes the OwnerProductRegistration and AttachmentList.
public class OwnerProductRegistration
{
public string CustomerFirstName { get; set; }
public string CustomerPhoneMobile { get; set; }
public List<AttachmentList> AttachmentLists { get; set; }
}
public class AttachmentList
{
public string FileName { get; set; }
public string Description { get; set; }
}
OwnerProductRegistration model = new OwnerProductRegistration();
AttachmentList attachmentList = new AttachmentList();
model.CustomerFirstName = "Test";
model.CustomerPhoneMobile = "1234567890";
attachmentList.FileName = "FileNameTest";
attachmentList.Description = "foo";
I want to send the entire 'OwnerProductRegistration' model with the AttachmentList data included. When I check the value contents of model, it shows the AttachmentList as null. How do I include the AttachmentList data with the model?
You must first instantiate the list on your model property, then add the attachment list to it. You can accomplish both like so:
model.CustomerFirstName = "Test";
model.CustomerPhoneMobile = "1234567890";
attachmentList.FileName = "FileNameTest";
attachmentList.Description = "foo";
model.AttachmentLists = new List<AttachmentList> { attachmentList };
If you don't want to use a collection initializer, you can break the operation up like this:
model.AttachmentLists = new List<AttachmentList>();
model.AttachmentLists.Add(attachmentList);
You're not setting the AttachmentLists property anywhere. Try this, it's similar to yours, but the property is set in the last line.
public class OwnerProductRegistration
{
public string CustomerFirstName { get; set; }
public string CustomerPhoneMobile { get; set; }
public List<AttachmentList> AttachmentLists { get; set; }
}
public class AttachmentList
{
public string FileName { get; set; }
public string Description { get; set; }
}
OwnerProductRegistration model = new OwnerProductRegistration();
AttachmentList attachmentList = new AttachmentList();
model.CustomerFirstName = "Test";
model.CustomerPhoneMobile = "1234567890";
attachmentList.FileName = "FileNameTest";
attachmentList.Description = "foo";
model.AttachmentLists = new List<AttachmentList> { attachmentList };
You can as well use Object Initializer and Collection initializer syntax available from C#3 like below
OwnerProductRegistration model = new OwnerProductRegistration
{
CustomerFirstName = "Test",
CustomerPhoneMobile = "1234567890",
AttachmentLists = new List<AttachmentList>
{
new AttachmentList
{
FileName = "FileNameTest",
Description = "foo",
}
}
}

How to map objects

Here is my how my bindings currently look:
MerchantAccountRequest request = new MerchantAccountRequest
{
Individual = new IndividualRequest
{
FirstName = merchant.MerchantIndividual.FirstName,
LastName = merchant.MerchantIndividual.LastName,
Email = merchant.MerchantIndividual.Email,
Phone = merchant.MerchantIndividual.Phone,
DateOfBirth = merchant.MerchantIndividual.DateOfBirth,
Ssn = merchant.MerchantIndividual.Ssn,
Address = new AddressRequest
{
StreetAddress = merchant.MerchantIndividual.StreetAddress,
Locality = merchant.MerchantIndividual.Locality,
Region = merchant.MerchantIndividual.Region,
PostalCode = merchant.MerchantIndividual.PostalCode
}
},
Business = new BusinessRequest
{
LegalName = merchant.MerchantBusiness.LegalName,
DbaName = merchant.MerchantBusiness.DbaName,
TaxId = merchant.MerchantBusiness.TaxId,
Address = new AddressRequest
{
StreetAddress = merchant.MerchantBusiness.StreetAddress,
Locality = merchant.MerchantBusiness.Locality,
Region = merchant.MerchantBusiness.Region,
PostalCode = merchant.MerchantBusiness.PostalCode
}
},
Funding = new FundingRequest
{
Descriptor = merchant.MerchantFunding.Descriptor,
Destination = FundingDestination.BANK,
Email = merchant.MerchantFunding.Email,
MobilePhone = merchant.MerchantFunding.MobilePhone,
AccountNumber = merchant.MerchantFunding.AccountNumber,
RoutingNumber = merchant.MerchantFunding.RoutingNumber
},
TosAccepted = merchant.TosAccepted,
MasterMerchantAccountId = merchant.MasterMerchantAccountId,
Id = merchant.MerchantId
};
And I need to use AutoMapper to achieve the above.
This is what I've tried:
CreateMapperProfile
EDIT:
CreateMap<Classes.Merchant, MerchantAccountRequest>()
.ForMember(dest => dest.Individual, source => source.MapFrom(s => s.MerchantIndividual))
.ForMember(dest => dest.Business, source => source.MapFrom(s => s.MerchantBusiness))
.ForMember(dest => dest.Funding, source => source.MapFrom(s => s.MerchantFunding))
.ForMember(dest => dest.Id, source => source.MapFrom(s => s.MerchantId));
Here is the Merchant class:
public partial class Merchant :
{
public int Id { get; set; }
public string MerchantId { get; set; }
public virtual MerchantIndividual MerchantIndividual { get; set; }
public virtual MerchantBusiness MerchantBusiness { get; set; }
public virtual MerchantFunding MerchantFunding { get; set; }
public bool TosAccepted { get; set; }
public string MasterMerchantAccountId { get; set; }
public bool isSubMerchant { get; set; }
}
And the mappings;
EDIT:
MerchantAccountRequest request = _mapper.Map<MerchantAccountRequest>(merchant);
request.Individual = _mapper.Map<IndividualRequest>(merchant.MerchantIndividual);
request.Business = _mapper.Map<BusinessRequest>(merchant.MerchantBusiness);
request.Funding = _mapper.Map<FundingRequest>(merchant.MerchantFunding);
Can the first line of code MerchantAccountRequest request = _mapper.Map<MerchantAccountRequest>(merchant); above do all the mapings?
..
..
..
..
How can I create the correct mappings?
You don't need to call _mapper.Map on the properties of the request.
Just call MerchantAccountRequest request = _mapper.Map<MerchantAccountRequest>(merchant); and assuming you have a map for each type you should be fine.
I think something along the lines of the following should get you going down the right path.
class Program
{
static void Main(string[] args)
{
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<Merchant, MerchantAccountRequest>()
.ForMember(dest => dest.Individual, c => c.MapFrom(source => source.MerchantIndividual));
cfg.CreateMap<MerchantIndividual, IndividualRequest>();
});
config.AssertConfigurationIsValid();
var mapper = config.CreateMapper();
var merchant = new Merchant
{
Id = 1,
MerchantIndividual = new MerchantIndividual { FirstName = "John Doe" }
};
var merchantAccountRequest = mapper.Map<Merchant, MerchantAccountRequest>(merchant);
}
}
public class Merchant
{
public int Id { get; set; }
public MerchantIndividual MerchantIndividual { get; set; }
}
public class MerchantIndividual
{
public string FirstName { get; set; }
}
public class MerchantAccountRequest
{
public int Id { get; set; }
public IndividualRequest Individual { get; set; }
}
public class IndividualRequest
{
public string FirstName { get; set; }
}

Linq from list objects into one object with a list property

Im trying to use Linq to select the property ProductColor from a List of MyObject into the property AllProductColors
public class MyObject
{
public string ImgUrl { get; set; }
public string ProductName { get; set; }
public string ProductColor { get; set; }
}
public class ObjectToSelectInto
{
public string ImgUrl { get; set; }
public string ProductName { get; set; }
public List<string> AllProductColors { get; set; }
}
//*** CREATING EXAMPLE ***///
List<MyObject> MyObjectList = new List<MyObject>();
ObjectToSelectInto destinationObject = new ObjectToSelectInto();
//I can do it like this, but then I
// would have to do this for every list item, not good!
destinationObject.AllProductColors =
MyObjectList.Select(x => x.ProductColor).toList();
//*** This fails ***///
destinationObject = MyObjectList.Select( x =>
new destinationObject {
AllProductColors = x.ProductColor.ToList(),
ImgUrl = x.ImgUrl.First().toString(),
ProductName = x.ProductName .First().toString()
}
I want it to be like this.
destinationObject has a list with elements where one color equals one element.
You just need to put your first query that you tried into second like this:
destinationObject = MyObjectList.Select(x =>
new ObjectToSelectInto()
{
AllProductColors = MyObjectList.Select(y => y.ProductName).ToList(),
ImgUrl = x.ImgUrl,
ProductName = x.ProductName
}).First();

Categories

Resources