Reputation: 787
I think the same question must have been asked, but I just don't know how to describe it properly.
I am using Entity Framework, and I have a table called vendor, consisting of many columns:
[vendor]
- [Id] [INT]
- [Name] [NVARCHAR]
- [ApiUrl] [NVARCHAR]
- ...
I am writing a Web Api to expose the function which users can get vendor records by. However, I want to provide only three columns.
So I created a model class, as below:
public class OM_Vendor
{
public int Id { set; get; }
public string Name { set; get; }
public string ApiUrl { set; get; }
}
After building the model classes with EF, the context object of EF has a property named vendors now. Then, in an API controller, I coded like this:
var vendors = this.objEntity.vendors
.Where<OM_Vendor>(v => v.Status == "1")
.OrderBy(v => v.Id)
.Skip(intSkip)
.Take(intLimit)
.ToList();
It doesn't work, neither does this:
var vendors = this.objEntity.vendors
.Where(v => v.Status == "1")
.OrderBy(v => v.Id)
.Skip(intSkip)
.Take(intLimit)
.ToList<OM_Vendor>();
Is there a way to convert the objects returned by the methods like above to my custom type?
Thanks a lot.
In addition, I know that I can get it to work in this way:
var vendors = new List<OM_Vendor>();
vendors = objCont.ExecuteStoreQuery<OM_Vendor>("SELECT * FROM vendor").ToList();
And this way works too:
var vendors = this.objCont.vendors
.Where(v => v.Status == "1")
.OrderBy(v => v.Id)
.Select(
row => new
{
Id= row.Id,
Name = row.Name,
ApiUrl = row.ApiUrl
}
)
.Skip(intSkip)
.Take(intLimit)
.ToList();
Update:
According to @Andrew's answer, I updated my code as below:
public class OM_Vendor
{
public int Id { set; get; }
public string Name { set; get; }
public string ApiUrl { set; get; }
public static implicit operator OM_Vendor(vendor vendor){
return new OM_Vendor
{
Id = vendor.Id,
Name = vendor.Name,
ApiUrl = vendor.ApiUrl
};
}
}
And in my controller class:
List<OM_Vendor> vendors = this.objCont.vendors
.Where(v => v.Status == "1")
.OrderBy(v => v.Id)
.Skip(intSkip)
.Take(intLimit)
.ToList();
I got error saying:
Cannot implicitly convert type 'System.Collections.Generic.List' to 'System.Collections.Generic.List'
What did I miss? As for the explicit cast, I will have to convert each instance explicitly in a loop?
Upvotes: 0
Views: 9034
Reputation: 22323
You basically have 3 methods to achieve what you are trying to accomplish.
.Select()
linq extension method to create a projection (as is demonstrated by your last example.) Generally a good option, as this will create a SQL expression which only returns the fields which are needed by your Data Transfer Object.public static implicit Operator OM_Vendor(Vendor vendor)
, which takes in a full Vendor
object and assigns it to an instance of OM_Vendor
. The main drawback here is that you are essentially retrieving all fields through Entity Framework, only to Flatten the entity and discard many of these fields during the implicit cast.A more complete code example to demonstrate:
public class OM_Vendor {
...
public static implicit Operator OM_Vendor(Vendor vendor){
return new OM_Vendor {
Id = vendor.Id;
Name = vendor.Name;
ApiUrl = vendor.ApiUrl;
}
}
OM_Vendor om_Vendor = this.objEntity.vendors.Where(
...
List<OM_Vendor> vendors = this.objEntity.vendors.Where(
...
Either of these statements should execute correctly, using the implicit Operator
as a Constructor when assigning a Vendor
instance to an OM_Vendor
. However, it cannot be overstated, this is Flattening the object at the code level, and will result in a larger than necessary SQL query.
This actually should be an explicit operator, since data loss occurs during conversion. Changing implicit Operator
to explicit Operator
will cause this conversion to require the cast, i.e. OM_Vendor omVendor = (OM_Vendor)vendor;
. This makes it much more clear that a conversion is occurring, but makes the code slightly more verbose.
Upvotes: 2
Reputation: 31
Have you tried projecting with:
.Select(row => new OM_Vendor{ Id=row.Id, Name=row.Name, ApiUrl=row.ApiUrl})
Upvotes: 0