Calling custom (formatting) method on LINQ to Entities - c#

I'm using EF 4.1 and I'm trying to enumerate a company list for a grid. I have two options in the current project: select all companies from the DbContext (Entities) and load them into an object from a non-anonymous type (let's say EmpresaGrid) or select all companies into anonymous type objects with the same structure like Empresa (which is the entity I'm selecting from).
The first option (creating a model class for that) would require a little more work, but can be, eventually, more readable. Still, I'm not sure about that. The second option is what I'm using right now.
So, first question: it's better to create a model class only for displaying data or use anonymous type? Doing a direct select is out of question: a SELECT * is too big and that might make everything damn slow (I guess). So selection into another type creates a custom query with only the needed fields.
Using the second option (anonymous type), I have this code (simplified version):
public static IEnumerable<object> Grid()
{
Entities db = new Entities();
var empresas = db.Empresas
.Select(e => new
{
Cgc = e.Cgc, // PK
(...)
Address = new
{
AddressLine = e.EnderecoSede.AddressLine,
(...)
}
},
Contato = e.Contato,
(...)
})
.ToList();
return empresas;
}
The anonymous type I'm creating has around 40 lines of code, so it's kinda big, but it recreates part of the Empresa class struct (since the grid is waiting for a Empresa object). Anyway, I have a problem with the data format. For example, I would like to format the Cgc property using a custom string format. I have a public method for this, FormataCgc. This method receives a string and returns it formatted using some internal conditions.
So, my problem is how to that. For example, I have tried this:
var empresas = db.Empresas
.Select(e => new
{
Cgc = FormataCgc(e.Cgc),
}
But that doesn't work because FormataCgc cannot be translated into SQL (and I don't want to convert it). I also tried this:
var empresas = db.Empresas
.Select(e => new
{
(...)
}
.ToList();
foreach (var e in empresas) {
e.Cgc = FormataCgc(e.Cgc);
}
But it cannot be done since anonymous types have only read-only properties.
So, my second question is: how exactly can I do that? I need to change the data after selecting it, but using anonymous types? I've done a little research, and the best thing I've found was this: Calling a custom method in LINQ query. In that solution, Ladislav suggested doing a second select from the IEnumerable, but since the grid is excepting Empresa I cannot do that (I need to change or add properties, not encapsulate them).
I'm not sure if I was clear enough, but feel free to ask any questions. Also, the grid I'm currently using is a Telerik ASP.NET MVC Grid, which receives a IEnumerable (where T is a class) as model data and them iterates each object, doing its magic.

Since you're already converting this into an IEnumerable<T>, you can do the custom formatting as you stream the results in the client. Do your db.Select, and then convert to the appropriate format afterwards, ie:
var empresas = db.Empresas
.Select(e => new
{
(...)
})
.ToList();
foreach (var e in empresas) {
yield return new {
Cgc = FormataCgc(e.Cgc),
// Copy other properties here, as needed...
};
}
That being said, I'd personally recommend making a custom class, and not return an anonymous type. Your conversion would then be:
foreach (var e in empresas) {
yield return new YourClass(FormataCgc(e.Cgc), ...); // Construct as needed
}
This will dramatically improve the usability of this method, as you will have proper, named access to your properties from the caller of the method.

I think the solution to both of your questions is to create a model class. Sure it is a little bit more work up front, but it will allow you greater flexibility in the long run. Your custom model class can then handle the formatting for you.
public class EmpresaGridModel
{
public string Cgc { get; set; }
public string CgcFormatted
{
return FormataCgc(this.Cgc);
}
//properties for the other fields will have to be created as well obviously
}
Your telerik grid can then bind directly to the CgcFormatted property

Related

Using EF Utilities for including child tables/list

I've been looking for a good solution to speed up my queries in my application. I came across this link:
https://github.com/MikaelEliasson/EntityFramework.Utilities
Where in example they show how their code works:
var result = db.Contacts
.IncludeEFU(db, c => c.PhoneNumbers)
.ToList();
So basically I pass two parameters into includefu, first is the object of the context I'm using, and then using lambda expression select the child record in the same class...
My structure looks like this:
Class Items
{
//some item data properties
List<Transactions> _transactions {get;set;}
}
And my query looks like this:
var list = ctx.Items.IncludeEfu(ctx,c=>c._transactions).ToList();
But when I use my lambda expression on 2nd parameter I get only these methods:
Equals
GetHashCode
ToString
GetType
What am I doing wrong here, has anyone else worked with EF Utilities before?
I'm not sure, if I understand the question correctly, but I think you are just missing some public in your structure.
If so, this might help:
public class Items
{
//some item data properties
public List<Transactions> _transactions {get;set;}
}

C#, Generics, Type and NHibernate

I'm learning the power of generics in C# in conjunction with NHibernate. I'd like to attempt the following in the pasted code.
In an attempt to do some post processing of N number of NHibernate objects I worked on a utility method leveraging generics to make it applicable to all NHibernate mapping classes we use now, or in the future. It works but I need to hard code each call for each mapping class. This is a pain and will need continuing updating as our schema and mappings change over time.
I do have an ever up-to-date list of all mapping classes by string name through the NHibernate mappings I generate on the fly. If there was a way to use this list of string names to call my generics based method, I'd be super happy.
Can anyone tell me if this is possible? Do I need to find another route?
Thanks so much in advance!!!
public static void ProcessSomeItems()
{
// *************************************************************
// As of now I have to list all classes as such to be processed
// It works but I have to update manually when new mapping classes are created
// *************************************************************
NHibDoSomethingUtil<AspnetMembership>();
NHibDoSomethingUtil<AspnetProfile>();
NHibDoSomethingUtil<AspnetRole>();
NHibDoSomethingUtil<AspnetUser>();
// and so forth...
// I have a up-to-date list of all mappings from "HbmMapping" and can get a list of all in the
// list form as below
List<string> mappingNames = new List<string>();
foreach (string mappingName in mappingNames)
{
Type theType = Type.GetType(mappingName);
// I know I'm getting Types and Generics classes and so forth all jumbled but
// how in the heck would I do something like the below?
NHibDoSomethingUtil<theType>(); // Obviously doesn't compile ;-)
}
}
// Generic method
public static void NHibDoSomethingUtil<T>() where T : class
{
using (ISession session = sourceDBSessionFactory.OpenSession())
{
foreach (dynamic item in new List<T>(session.QueryOver<T>().List()))
{
// Process item;
}
}
}
ecsousa gave great input and I was able to accomplish what I needed with something like the following.
foreach (HbmClass mappingClass in mapping.Items)
{
Console.WriteLine(" -- Discovered Mapping: " + mappingClass.Name);
Type mappingClassType = Type.GetType(mappingClass.Name);
var genericMethod = typeof(Migration).GetMethod("NHibDoSomethingUtil");
var method = genericMethod.MakeGenericMethod(mappingClassType);
method.Invoke(null, null);
}
You will need to use Reflection in order to accomplish this. Instead of directly calling NHibDoSomethingUtil, try this:
var genericMethod = typeof(TheClassName).GetMethod("NHibDoSomethingUtil");
var method = genericMethod.MakeGenericMethod(theType);
method.Invoke(null, null);
Note that you have to replace TheClassName by the class containing both methods.
Keep in mind the this kind of code is slow, and you should use it very carefully.

Calculation in EF Projection

Is there a way I can achieve the following?
// colourInfo.Discount = 75, but can change
// allPrice type has Part, Desc, Type
var a = allPricesForPgs.Where(x => x.PG == c && x.ColourCode == colourInfo.ColourCode).Select(y=> new AllPrice {Part=y.Part, Desc=y.Desc, Price=y.Price*(colourInfo.Discount/100)}));
I get the error : The entity or complex type 'Portal.AllPrice' cannot be constructed in a LINQ to Entities query.
It seems the EF cannot handle calculations, what are my options since I am getting a dynamic value from one table to do a calculation on another?
Sam1's comment is correct. You cannot project into another entity. Other options you have can be to create an anonymous type like so:
var a = allPricesForPgs
.Where(x => x.PG == c && x.ColourCode == colourInfo.ColourCode)
.Select(y=> new
{
Part=y.Part,
Desc=y.Desc,
Price=y.Price*(colourInfo.Discount/100)
}
));
Or to create a class that will hold the temporary data (such as a DTO).
Since it seems like all you need to do is have this information to modify some other entity, you should be able to do it with the anonymous type.
EDIT:
You could add a '.ToList()' right before the .Select(...). You'd essentially be using LINQ TO OBJECTS instead of LINQ TO ENTITIES, so if a lot of entities might match the allPricesForPgs.Where(...) statement, you should keep away from that.
But, if you want these as AllPrice's, why are they not added to the AllPrice DB? Are you keeping a separate list of some AllPrice's from Entity Framework and some AllPrice's from this list? This could get confusing and cause errors.
A final option would be to extend the class. All entities are declared PARTIAL. You can create another class like:
partial class AllPrice
{
Double DiscoutedPrice { get { Price * myDiscount/100; } }

C#, Linq2SQL - tricks to fetch a ViewModel object with relation data?

I don't know Linq2Sql so well yet and I was wondering if there is a trick for this probably common MVVM scenario. I have Linq2Sql data context containing Domain models, but I am fetching data for my customized ViewModel object from it.
var query = from ord in ctx.Table_Orders
select new OrderViewModel()
{
OrderId = ord.OrderId,
OrderSum = ord.OrderSum,
OrderCurrencyId = ord.OrderCurrencyId,
OrderCurrencyView = ord.Currency.CurrencyText
};
So i want my ViewModel to inculde both CurrencyId from domain object and the CurrencyText from related table to show it nicely in the View.
This code works great. It generates one DB call with join to fetch the CurrencyText. But the model is simplified, real one has many more fields. I want to make the code reusable because I have many different queries, that returns the same ViewModel. Now every minor change to OrderViewModel requires lots of maintainance.
So I moved the code to OrderViewModel itself as a constructor.
public OrderViewModel(Table_Order ord)
{
OrderId = ord.OrderId,
OrderSum = ord.OrderSum,
OrderCurrencyId = ord.OrderCurrencyId,
OrderCurrencyView = ord.Currency.CurrencyText
}
And call it like this.
var query = from ord in ctx.Table_Orders
select new OrderViewModel(ord);
The Problem: The join is gone DB query is no more optimised. Now I get 1+N calls to database to fetch CurrencyText for every line.
Any comments are welcome. Maybe I have missed different great approach.
This is how far i could get on my own, to get the code reusability. I created a function that does the job and has multiple parameters. Then I need to explicitly pass it everything that has crossed the line of entity.
var query = ctx.Table_Orders.Select(m =>
newOrderViewModel(m, m.Currency.CurrencyText));
The DB call is again optimized. But it still does not feel like I am there yet! What tricks do You know for this case?
EDIT : The final solution
Thanks to a hint by #Muhammad Adeel Zahid I arrived at this solution.
I created an extension for IQueryable
public static class Mappers
{
public static IEnumerable<OrderViewModel> OrderViewModels(this IQueryable<Table_Order> q)
{
return from ord in q
select new OrderViewModel()
{
OrderId = ord.OrderId,
OrderSum = ord.OrderSum,
OrderCurrencyId = ord.OrderCurrencyId,
OrderCurrencyView = ord.Currency.CurrencyText
};
}
}
Now i can do this to get all list
var orders = ctx.Table_Order.OrderViewModels().ToList();
or this to get a single item, or anything in between with Where(x => ..)
var order = ctx.Table_Order
.Where(x => x.OrderId == id).OrderViewModels().SingleOrDefault();
And that completely solves this question. The SQL generated is perfect and the code to translate objects is reusable. Approach like this should work with both LINQ to SQL and LINQ to Entities. (Not tested with the latter) Thank You again #Muhammad Adeel Zahid
Whenever we query the database, we mostly require either enumeration of objects (more than one records in db) or we want a single entity (one record in db). you can write your mapping code in method that returns enumeration for whole table like
public IEnumerable<OrderViewModel> GetAllOrders()
{
return from ord in ctx.Table_Orders
select new OrderViewModel()
{
OrderId = ord.OrderId,
OrderSum = ord.OrderSum,
OrderCurrencyId = ord.OrderCurrencyId,
OrderCurrencyView = ord.Currency.CurrencyText
};
}
Now you may want to filter these records and return another enumeration for example on currencyID
public IEnumerable<OrderViewModel> GetOrdersByCurrency(int CurrencyID)
{
return GetAllOrders().Where(x=>x.CurrencyId == CurrencyID);
}
Now you may also want to find single record out of all these view models
public OrderViewModel GetOrder(int OrderID)
{
return GetAllOrders().SingleOrDefault(x=>x.OrderId == OrderID);
}
The beauty of IEnumerable is that it keeps adding conditions to query and does not execute it until it is needed. so your whole table will not be loaded unless you really want it and you have kept your code in single place. Now if there are any changes in ViewModel Mapping or in query itself, it has to be done in GetAllOrders() method, rest of code will stay unchanged
You can avoid the N+1 queries problem by having Linq2SQL eagerly load the referenced entites you need to construct your viewmodels. This way you can build one list of objects (and some referenced objects) and use it to construct everything. Have a look at this blog post.
One word of warning though: This technique (setting LoadOptions for the Linq2SQL data context) can only be done once per data context. If you need to perform a second query with a different eager loading configuration, you must re-initalize your data context. I automated this with a simple wrapper class around my context.

WCF Web Service - List<> Return type

List<CertMail> lsRecipetNumber = new List<CertMail>();
CertMail class is in data access layer which returns a List<CertMail>. I need to
convert this to the object of my class and return that
List<CertMailReceiptNumbers> lsReceiptNumbers = new List<CertMailReceiptNumbers>();
CertMailReceipt.lsCMRN = lsReceiptNumbers; //---- > return this.
How do i add all the rows in the CertMail list to CertMailRecieptNumbers and return that from CertMailRecieptNumbers class?
If you only need to map from CertMail to CertMailReceipt and the two types are very similar, you could use an automagic helper like AutoMapper to help you with the mapping.
Basically, AutoMapper will handle much of the boring and error-prone left-right code - assigning one property on the target to a property on the source object.
In your case, if the two types are somewhat similar, you could do something like:
using AutoMapper;
Mapper.CreateMap<CertMail, CertMailReceipt>();
sourceList.ForEach(certMail =>
{
lsReceiptNumbers.Add(Mapper.Map<CertMail, CertMailReceipt>(certMail))
});
or if you prefer:
using AutoMapper;
Mapper.CreateMap<CertMail, CertMailReceipt>();
foreach(certMail cm in sourceList)
{
lsReceiptNumbers.Add(Mapper.Map<CertMail, CertMailReceipt>(cm));
}
This is basically the same idea that NPayette mentioned, just using an half-automatic mapper, instead of having to write the whole mapping process yourself.
And with a bit of luck (and depending on your types of data structures), you might even get the benefit of Automapper being able to even map entire lists from one type to another:
lsReceiptNumbers = Mapper.Map<List<CertMail>,
List<CertMailReceipt>>(sourceList);
Automapper will go through the list of items itself, and apply its mapping to each item, and add those to the resulting output list.
If I understand correctly your need it's a simple mather of mapping from one to another.
Well you need to go throu your CertMail list and then for each of them create a new CertMailReceiptNumbers
Ex.
...
lsReceiptNumber.ForEach(certMail =>
{
lsReceiptNumbers.Add(convertToCertMailReceiptNumber(certMail));
});
return lsReceiptNumber
}
Public CertMailReceiptNumbers convertToCertMailReceiptNumber(CertMail cm)
{
var cmrn = new ertMailReceiptNumber();
cmrn.xxx = cm.xxxx;
...;
return cmrn;
}

Categories