How to create a Store Expression for entity framework - entity-framework-4

I have this.
var ViewModel = repGeneric.GetListOf<CompanyContact>(p => p.CompanyID == 1).Select(s => new ContactViewModel()
{
ContactType = _db.ContactTypeTexts.FirstOrDefault(p => p.ID == s.Contact.ContactType.ID).Txt
});
I would like to put this piece of code
_db.ContactTypeTexts.FirstOrDefault(p => p.ID == s.Contact.ContactType.ID).Txt
in a function.
How can I do that.? Any Idea. I Try but that's give me this error :
LINQ to Entities does not recognize
the method 'System.String GetTxt()'
method, and this method cannot be
translated into a store expression.
Thanks

Try Model-Defined Function like it is described in this blog article by Julie Lerman.

Related

Convert SQL query into lambda expression in ASP.NET MVC 5

How can I convert a SQL query like this:
Select *
from product
where c_id = 2
into a lambda expression?
I tried writing it like this:
db.Products.Where(x => x.c_id == 2).ToList()
Is this correct?
var filteredResult = db.Products.Where(x => x.c_id ==2 ).ToList();
should work, provided db.Products is collection.
Is this correct?
Yes
If you want to OrderBy along with Where, you can try this way
public ActionResult Index() {
return View(db.Products.Where(x => x.c_id == 2).OrderByDescending(x => x.pro_id).ToList());
}

The 'Skip' method is only supported for sorted input in LINQ to Entities. The method 'OrderBy' must be called before the method 'Skip'

And here is the line that is producing the error
var genreModel = storeDB.Categories.Include("Albums").ToPagedList(pageNumber, pageSize)
.Single(g => g.Name == Category);
What am i doing wrong here?
I infer that the ToPagedList uses skip and take internally.
Just include an orderBy before it, something like:
var genreModel = storeDB.Categories.Include("Albums").OrderBy(x=>x.Id).ToPagedList(pageNumber, pageSize) .Single(g => g.Name == Category);

LINQ To Entities cannot generate string MVC Razor

When Using LINQ to get information I use the following method
var salt_water_disposals = _SaltWaterDisposals.SaltWaterDisposals.Select(sw => new SaltWaterModel
{
saltwater_ID = sw.SaltWaterDisposalID,
lease = sw.Lease.LeaseName,
field = sw.Lease.Field.Name.ToLower(),
permitter_fluid = sw.PermittedFluids.Count == 0 ? "None" : sw.PermittedFluids.Aggregate("", (current, c) => current+c.Fluid.Name),
max_gas_pressure = sw.MaxGasInjectionPressure,
});
However when I run the code I get the following error because of the PermittedFluids:
LINQ to Entities does not recognize the method 'System.String
Aggregate[PermittedFluid,String](System.Collections.Generic.IEnumerable1[FieldPro.Domain.Entities.PermittedFluid],
System.String,
System.Func3[System.String,FieldPro.Domain.Entities.PermittedFluid,System.String])'
method, and this method cannot be translated into a store expression.
I have tried using it also as a ToString() but I get the same error.
Any Ideas?
Any Help would be appreciated.
As you may know, LINQ translates your code into a SQL statement. It can't translate all code, and this is one of those cases.
System.Data.Objects.SqlClient.SqlFunctions is a class that has many static methods that are valid within the LINQ context.
I fixed this by taking out the Aggregate call and calling it in my view, and changing the data type or permitter_fluid.
So My model has:
public System.Data.Objects.DataClasses.EntityCollection<FieldPro.Domain.Entities.PermittedFluid> permitter_fluid { get; set; }
My Controller has:
permitter_fluid = sw.PermittedFluids,
and my view has (using a Html.Grid from MvCContrib):
column.For(m => m.permitter_fluid.Aggregate("", (current, c) => current + c.Fluid.Name)).Named("Permitted Fluid");
This solved my problem

Getting a list of distinct entities projected into a new type with extra field for the count

I'm designing an interface where the user can join a publicaiton to a keyword, and when they do, I want to suggest other keywords that commonly occur in tandem with the selected keyword. The trick is getting the frequency of correlation alongside the properties of the suggested keywords.
The Keyword type (EF) has these fields:
int Id
string Text
string UrlString
...and a many-to-many relation to a Publications entity-set.
I'm almost there. With :
var overlappedKeywords =
selectedKeyword.Publications.SelectMany(p => p.Keywords).ToList();
Here I get something very useful: a flattened list of keywords, each duplicated in the list however many times it appears in tandem with selectedKeyword.
The remaining Challenge:
So I want to get a count of the number of times each keyword appears in this list, and project the distinct keyword entities onto a new type, called KeywordCounts, having the same fields as Keyword but with one extra field: int PublicationsCount, into which I will populate the count of each Keyword within overlappedKeywords. How can I do this??
So far I've tried 2 approaches:
var keywordCounts = overlappingKeywords
.Select(oc => new KeywordCount
{
KeywordId = oc.Id,
Text = oc.Text,
UrlString = oc.UrlString,
PublicationsCount = overlappingKeywords.Count(ok2 => ok2.Id == oc.Id)
})
.Distinct();
...PublicationsCount is getting populated correctly, but Distinct isn't working here. (must I create an EqualityComarer for this? Why doesn't the default EqualityComarer work?)
var keywordCounts = overlappingKeywords
.GroupBy(o => o.Id)
.Select(c => new KeywordCount
{
Id = ???
Text = ???
UrlString = ???
PublicationsCount = ???
})
I'm not very clear on GroupBy. I don't seem to have any access to 'o' in the Select, and c isn't comping up with any properties of Keyword
UPDATE
My first approach would work with a simple EqualityComparer passed into .Distinct() :
class KeywordEqualityComparer : IEqualityComparer<KeywordCount>
{
public bool Equals(KeywordCount k1, KeywordCount k2)
{
return k1.KeywordId== k2.KeywordId;
}
public int GetHashCode(KeywordCount k)
{
return k.KeywordId.GetHashCode();
}
}
...but Slauma's answer is preferable (and accepted) because it does not require this. I'm still stumped as to what the default EqualityComparer would be for an EF entity instance -- wouldn't it just compare based on primary ids, as I did above here?
You second try is the better approach. I think the complete code would be:
var keywordCounts = overlappingKeywords
.GroupBy(o => o.Id)
.Select(c => new KeywordCount
{
Id = c.Key,
Text = c.Select(x => x.Text).FirstOrDefault(),
UrlString = c.Select(x => x.UrlString).FirstOrDefault(),
PublicationsCount = c.Count()
})
.ToList();
This is LINQ to Objects, I guess, because there doesn't seem to be a EF context involved but an object overlappingKeywords, so the grouping happens in memory, not in the database.

How to specify a condition in an Entity Framework join?

I have a Blogs table related to BlogComments table with a FK.
I need to get, through Linq, all the BlogComments items that match a certain flag
If i do:
db.Blogs.Where(b => b.BlogComments.Where(bc=>bc.Where(bc.Flag1==true));
I get "Cannot implicity convert type IEnumerable to bool"
Which is the best way to solve this problem?
Because this expression:
b.BlogComments.Where(...)
returns an IEnumerable (of BlogComments), but you are then passing it into this method:
db.Blogs.Where(...)
which expects a function that returns a bool, not an IEnumerable.
You probably need something like this:
var blogId = 5;
db.BlogComments.Where(bc => bc.BlogId == blogId && bc.Flag1 == true)
If you need to select comments from multiple blogs, then you could try using Contains:
var blogIds = new [] {1,2,3,4,5};
db.BlogComments.Where(bc => blogIds.Contains(bc.BlogId) && bc.Flag1 == true)
If you want to place criteria on the set of blogs, as well as the comments, then you could do this in one query using a join:
var query = from b in db.Blogs
join c in db.BlogComments on c.Blog equals b
where b.SomeField == "some value"
&& c.Flag1 == true
select c;
You could write it in LINQ form.
var blogs = from b in db.Blogs
join c in db.BlogComments
on b.BlogId equals c.BlogId
where c.Flag1
select b;
If you have a composite key you can write
on new { A = b.BlogKey1, B = b.BlogKey2 }
equals new { A = c.CommentKey1, B = c.CommentKey2 }
If it were me, I would just have another DbSet in your DbContext.
DbSet<BlogComment> BlogComments
and just search through there without going through Blogs.
db.BlogComments.Where(bc => bc.Flag1 == true);
If anyone knows if there's anything wrong in doing so, then I'm all ears :)

Resources